I am opening a uibModal each time a page is opened like:
genres.js
app.controller('genresController', ['$scope', '$http', '$uibModal', 'blockUI', 'notifyService', 'lib',
function ($scope, $http, $uibModal,blockUI, notifyService, lib) {
$scope.genres = [];
var init = function () {
//Initial code
loadGenres();
};
var loadGenres = function () {
/*... some non-important codes... */
openFavoriteGenreDialog();
/*... some non-important codes... */
}, lib.handleError);
};
var openFavoriteGenreDialog = function () {
var modalInstance = $uibModal.open({
templateUrl: '/Dialog/FavoriteGenre',
controller: 'favoriteGenreDialogController'
});
modalInstance.result.then(function (msg) {
}, function (msg) {
//dismiss callback
});
};
init();
}]);
and the modal controller is in another file and the html of that modal has a cancel button.
FavoriteGenre.cshtml
<button class="btn btn-default" type="button" ng-click="cancel()">Cancel</button>
That cancel button is beeing treated in another controller that has the function that so far looks like it
favGenrer.js
$scope.cancel = function () {
var modalInstance = $uibModal.open({
templateUrl: '/Dialog/FavoriteGenre',
controller: 'favoriteGenreDialogController'
});
modalInstance.close();
};
Because of that construction, I'm opening and closing the modal each time I press the cancel button. There is anyway so I can close the modal when I press the close button even if the cancel() funcion is in another controller that is in another file? I tried to put the cancel() function on genres.js but I wasn't able to make the html call the genresController without getting lot of erros because of the genresControllers other methods.
ANSWER
find out! the problem was that in the FavoriteGenre.cshtml I was doing
<div ng-controller="favoriteGenreDialogController" block-ui="genresContentDiv">
I just needed to let it be like:
<div block-ui="genresContentDiv">
and it worked using the
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
Try this.
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
Related
I want to invoke a custom directive inside another custom directive's template.
Please find below code snippets -
Scenario 1 (Not working)
angular.module('myApp')
.directive('customOnChange', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
element.bind('change', function (event) {
var files = event.target.files;
onChangeFunc(files);
});
element.bind('click', function () {
element.val('');
});
}
};
})
.directive('writePost', function () {
return {
restrict: 'E',
link: function (scope) {
scope.changeUserProfileImage = function (files) {
console.log(files); // I should receive uploaded files here.
};
},
templateUrl: function () {
return 'writePost.html';
}
};
});
index.html
<write-post></write-post>
writePost.html
<input type="file" ng-model="file" name="file"
id="photo-upload1" custom-on-change="changeUserProfileImage"
value="Change Image"
title="Change Image"/>
The error I am receiving when I upload a file -
Uncaught TypeError: onChangeFunc is not a function
Scenario 2 (Working)
Although independently I am able to call customOnChange directive from index.html. Working code snippet -
index.html
<input type="file" ng-model="file" name="file"
id="photo-upload1" custom-on-change="changeUserProfileImage"
value="Change Image"
title="Change Image"/>
myCtrl.js
angular.module('myApp')
.controller('myCtrl', ['$scope', function ($scope) {
$scope.changeUserProfileImage = function (files) {
console.log(files); // I am receiving uploaded files here.
};
}]);
Can someone help me identifying, where I am going wrong in first scenario ?
link in directive definition defaults to postLink - it executes after template with its directives is parsed. (read more here https://docs.angularjs.org/api/ng/service/$compile#pre-linking-function)
As a solution you can move $eval inside callback:
element.bind('change', function (event) {
var onChangeFunc = scope.$eval(attrs.customOnChange);
var files = event.target.files;
onChangeFunc(files);
});
Correct way:
If you want run function - let it be function in html:
custom-on-change="changeUserProfileImage(files)"
Now run it as function:
element.bind('change', function (event) {
var files = event.target.files;
scope.$eval(attrs.customOnChange, {files: event.target.files});
});
I want to get the file from json and compare them with the textbox that I get from the input form, but my code seems not working properties. I am very new to angular and this is my first try project not for work.
//This is JS file
(function () {
'use strict';
angular.module('routerApp').controller('LoginCtrl', function ($http, $scope, $location) {
$scope.loginUser = function () {
$http.get('data.json').then(function(data){
$scope.users = data;
var usr = $scope.usr;
var pwd = $scope.pwd;
if(data.username == usr && data.password == pwd){
$location.path('/laptop');
}
else{
alert("Username or password is incorrect");
}
});
};
});
})();
When I click login button it always true even I didn't input anything
I am trying to use a service to set title in controller1 and then access title in controller2.
sharedProperties.setTitle(title) works in controller1, but when I try to get the title in controller2, it gets "title" (the initial value) instead of the new value.
I've also tried storing title in an object but it didn't work.
app.service('sharedProperties', function () {
var title = "title"
return {
getTitle: function () {
return title;
},
setTitle: function (val) {
title = val;
}
}
});
app.controller('controller1', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$('body').on("click", "button[name=btnListItem]", function () {
// gets the title
var title = $(this).text();
// sets the title for storage in a service
sharedProperties.setTitle(title);
});
}]);
app.controller('controller2', ['$scope', 'sharedProperties', function ($scope, sharedProperties) {
$scope.sharedTitle = function() {
return sharedProperties.getTitle();
};
}]);
And in my view, I have {{ sharedTitle() }} which should, as I understand it, update the title text with the new title.
Also, in case this is relevant: the two controllers are linked to two different html pages.
What am I doing wrong?
EDIT
Updated button listener:
$('body').on("click", "button[name=btnListItem]", function () {
// gets the text of the button (title)
var title = $(this).text();
sharedTitle(title);
alert(sharedProperties.getTitle());
document.location.href = '/nextscreen.html';
});
$scope.sharedTitle = function (title) {
sharedProperties.setTitle(title);
};
It seems to be correct in your sample code. I setup jsfiddle and it seems work correctly. Finding out a difference between my jsfiddle and your actual code would help you to find the problem you should solve.
Javascript:
angular.module('testapp', [])
.service('sharedProperties', function(){
var title = 'title';
return {
getTitle: function(){
return title;
},
setTitle: function(val){
title = val;
}
};
})
.controller('controller1', function($scope, sharedProperties){
$scope.change_title = function(newvalue){
sharedProperties.setTitle(newvalue);
};
})
.controller('controller2', function($scope, sharedProperties){
$scope.sharedTitle = function(){
return sharedProperties.getTitle();
};
})
Html:
<div ng-app="testapp">
<div ng-controller="controller1">
<input ng-model="newvalue">
<button ng-click="change_title(newvalue)">Change Title</button>
</div>
<div ng-controller="controller2">
<span>{{sharedTitle()}}</span>
</div>
</div>
My jsfiddle is here.
You have to print console.log(sharedProperties.getTitle()); Dont need return from controller.
So your code of controller2 is $scope.sharedTitle = sharedProperties.getTitle();
You need to use the $apply so that angular can process changes made outside of the angular context (in this case changes made by jQuery).
$('body').on("click", "button[name=btnListItem]", function () {
// gets the title
var title = $(this).text();
// sets the title for storage in a service
$scope.$apply(function() {
sharedProperties.setTitle(title);
});
});
See plunker
That said, this is BAD PRACTICE because you're going against what angular is meant for. Check “Thinking in AngularJS” if I have a jQuery background?. There are cases when you need to use $apply like when integrating third party plugins but this is not one of those cases.
I have a follow button for a particular user that should change its text to followed after it's clicked and vice versa. This follow button can show up in different modules on the page. When it's clicked, the follow button for this particular users should update in all of these modules. However, the buttons are in different scopes. What is the angular way of making sure the cloned buttons are in the same state?
My current solution is to use an universal jQuery selector to update all the buttons on click.
You should store the state in a service.
example:
app.factory('SharedService', function() {
this.buttonState = null;
this.setButtonState= function(value) {
this.buttonState = value;
}
this.getButtonState= function() {
return this.buttonState ;
}
return this;
});
Read: AngularJS Docs on services
or check this Egghead.io video
You can use $rootScope.$broadcast to do this. when any of button gets clicked you fire an event using $rootScope.$broadcast and then listen to it using $scope.$on and toggle the status of buttons. and you can also update state inside the service too, so you can fetch current value later if needed.
See the below example:
var app = angular.module('app', []);
app.controller('ctrl1', function($scope) {
$scope.label1 = "First Button";
});
app.controller('ctrl2', function($scope) {
$scope.label2 = "Second Button";
});
app.controller('ctrl3', function($scope) {
$scope.label3 = "Third Button";
});
// updating state in service too.
app.service('fButtons', function($rootScope) {
var buttonState = false;
this.getCurrentState = function() {
return buttonState;
};
this.updateCurrentState = function() {
buttonState = !buttonState;
};
});
app.directive('followButton', function($rootScope, $timeout, fButtons) {
return {
restrict: 'E',
scope: {
label: '='
},
template: '<button ng-click="buttonClick()" ng-class="{red: active}">{{label}}</button>',
controller: function($scope) {
$scope.$on('button.toggled', function() {
$scope.active = !$scope.active;
});
$scope.buttonClick = function() {
fButtons.updateCurrentState();
$rootScope.$broadcast('button.toggled');
console.log(fButtons.getCurrentState());
}
}
};
});
.red {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl1">
<follow-button label="label1"></follow-button>
</div>
<hr/>
<div ng-controller="ctrl2">
<follow-button label="label2"></follow-button>
</div>
<hr/>
<div ng-controller="ctrl3">
<follow-button label="label3"></follow-button>
</div>
</div>
see console for service state.
$broadcast docs
I am trying to open a modal popup based on some condition. However i am getting the below error
Error: [$injector:unpr] http://errors.angularjs.org/1.2.3/$injector/unpr?p0=%24modalProvider%20%3C-%20%24modal
at Error (<anonymous>)
Below is my Code: "ui.bootstrap" is included in the app.
angular.module('myApp').controller('myController', function ($scope, $timeout, $location, $window, $log, $rootScope, $modal) {
$scope.selectRow = function (position) {
$scope.changed = false;
if ($scope.select !== undefined && $scope.selectedRow !== position){
$scope.changed = true;
$scope.open();
}
$scope.select = position;
};
$scope.open = function () {
console.log('Opening modal');
var modalInstance = {
templateUrl: 'modal.html',
dialogClass: 'modal-selection',
controller: ModalInstanceCtrl
};
$modal.open(modalInstance);
};
var ModalInstanceCtrl = function ($modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
});
My HTML:
<div id="modal-select" >
<h3>
Choose appropriate change
</h3>
<div>
<ul>
<li>Change 1</li>
<li>Change 2</li>
<li>Change 3</li>
<li>Change 4</li>
</ul>
</div>
<div>
<button class="button" ng-click="cancel()">
Cancel
</button>
<button class="button" ng-click="ok()">
Done
</button>
</div>
</div>
From the Angular website:
This error results from the $injector being unable to resolve a required dependency. To fix this, make sure the dependency is defined and spelled correctly. For example
Do you have 'ui.bootstrap' as a dependency to your current module?
angular.module('myApp').controller('myController', function ($scope, $timeout, $location, $window, $log, $rootScope, $modal)
Should be:
angular.module('myApp', ['ui.bootstrap']).controller('myController', function ($scope, $timeout, $location, $window, $log, $rootScope, $modal)
The error was because i had ui.bootstrap 0.5.0. I updated to 0.6.0 and rebuild the application to include this and the issue was fixed.
I solve this problem, by simply append the $modal.open({... to $scope.modalInstance variable.
(function () {
var app = angular.module('app');
app.controller('ModalCtrl', [
'$scope', '$modal', function ($scope, $modal) {
$scope.modalInstance = {};
$scope.open = function () {
$scope.modalInstance = $modal.open({
templateUrl: 'Template id goes here',
controller: 'ModalInstanceCtrl'
});
};
}
]); })();
The 'ModalInstanceCtrl'
(function () {
var app = angular.module('app');
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance) {
$scope.submit = function (myForm) {
//submit code goes here
};
$scope.cancel = function () {
$modalInstance.close();
};
}
); })();