I am trying to change a controller variable inside a directive and this is my code:
the main controller is :
angular.module("app").controller('vehicleManagementController', ['$scope', 'toastr', '$filter' ,
function ($scope, toastr, $filter) {
.....
$scope.filteredDevices = //Some List
$scope.allDevices = [];
}
}]);
and the directive is :
angular.module('app').directive('advanceSearchDirective', ['deviceAdvancedSearchService', 'mapService', function (deviceAdvancedSearchService, mapService) {
return {
restrict: "E",
controller: 'myDirectiveController',
scope: { filteredDevices: '=filteredDevices' },
templateUrl: '/app/templates/advanceSearchDirective.html'
};
}]);
angular.module("app").controller(myDirectiveController( $scope) {
$scope.search = function() {
$scope.filteredDevices = [];
$scope.$apply();
}
});
the thing is it faild to run the apply() method through this error.
and here how i am using it :
<advance-search-directive filtered-devices="filteredDevices" model="$parent"></advance-search-directive>
I have access to $scope.filteredDevices inside the directive controller but when i change its value it doesn't change in the main controller. what am I doing wrong?
if you want to save the changes on the parent controller scope you should use
scope:false,
change the directive to :
return {
restrict: "E",
controller: 'myDirectiveController',
scope: false,
templateUrl: '/app/templates/advanceSearchDirective.html'
};
here is an useful article .
Related
I have 2 directives, <parent-directive> and <child-directive>. <parent-directive> has its controller called "parentCtrl" and <child-directive> has its controller called "childCtrl"
var myApp = angular.module("myApp",[]);
myApp.directive("parentDirective", function() {
return {
restrict: "E",
templateUrl: "parent.html",
controller: [
"$scope",
function($scope) {
var self = this;
var parentSayHello = function(){
console.log("Hello from parent");
};
var callChildSayHello = function(){
// want to call the say hello method defined in childCtrl here
// ...
};
}
],
controllerAs: "parentCtrl"
};
});
myApp.directive("childDirective", function() {
return {
restrict: "E",
templateUrl: "child.html",
controller: [
"$scope",
function($scope) {
var self = this;
var childSayHello = function(){
console.log("Hello from child");
};
var callParentSayHello = function(){
// want to call the say hello method defined in parentCtrl here
// ...
};
}
],
controllerAs: "childCtrl"
};
});
In html, parentDirective and childDirective are nested directives:
<parent-directive>
<child-directive></child-directive>
</parent-directive>
How could parent directive's controller call a method from child directive's controller and vice versa? (i.e., how to implement callChildSayHello & callParentSayHello as shown in the JS code above)
From doc, Best Practice is to use controller when you want to expose an API to other directives.
Detail examples could be found in the link.
You can also call parent (directive/component) method in child directive via '&' function input:
JS:
angular.module('yourModule').directive('childDirective', [function () {
'use strict';
return {
restrict: 'EA',
scope: {
callback: '&'
},
templateUrl: 'xxx.html'
};
}]);
HTML:
<child-directive callback="methdoInParentDirective()"></child-directive>
I define a directive in angular 1.4,which receives a scope parameter “b”:
(function() {
'use strict';
angular
.module('m')
.directive('mydirective', mydirective);
/** #ngInject */
function mydirective() {
var directive = {
restrict: 'E',
templateUrl: 'app/components/mydirective/mydirective.html',
scope: {
b: '='
},
controller: MydirectiveController,
controllerAs: 'vm',
bindToController: true
};
return directive;
/** #ngInject */
function MydirectiveController($scope, $state) {
var vm = this;
//here How to watch the parameter b to refresh the directive html result?
}
in html page:
<mydirective b="ctrl.b"></myupl>
in the business controller, b is got from an angular resource
PayService.getBusinessNumber().then(function(results){
vm.b = {business_id: results.no};
});
in index.route.js which define the route and the business controller,
$stateProvider
.state('payShowInfo', {
url: '/payShowInfo',
templateUrl: 'app/pay_show_info.html',
controller: 'PayShowController',
controllerAs: 'ctrl'
});
my problem is , When the directive loaded, the parameter “b” is undefined, How to watch controller asynchronous data in angular directive? and then use the new value of “b” to refresh the html page?
If you define the directive parameter as "=", you mean that you will have two way data binding. So if you change the value in the controller, you will have the change reflected in the view.
angular.module('nib', [])
.directive('mydirective', function ($timeout) {
return {
restrict: 'E',
scope: {
b: '='
},
link: function ($scope, element, attrs) {
},
template: '<div>Test: {{b}}</div>'
};
})
.controller('ctrl',function($scope){
$scope.click = function(){ // emulating asynchronous request
$scope.test = 'testing';
}
})
See in the plnkr below:
http://plnkr.co/3qs1NpU1aIhKzxyCMXjh?p=preview
I have the following directive. When I trigger the open function and get to the debugger I get an error message in the console that says Uncaught ReferenceError: $scope is not defined(…).
How is it possible for $scope.open to be called when $scope is undefined?
app.directive('photo', ['$http', 'modal', function($http, modal) {
return {
replace: true,
templateUrl: '/assets/photo.html',
transclude: false,
scope: {
result: '=',
index: '#'
},
controller: ['$scope', '$http', 'modal', function($scope, $http, modal) {
$scope.prev = $scope.index - 1;
$scope.open = function() {
debugger;
};
}]
}
}]);
Here is my DOM:
<div ng-repeat="r in results" photo result="r" index="$index"></div>
If I insert console.log($scope) just before my open function, and then again right before the debugger in that function, I get the following results. Left is before open is called, right is after open is called.
You inject the $http and modal in the directive definition (as you did), no need to in the controller function, just do:
controller: function($scope) {
$scope.prev = $scope.index - 1;
$scope.open = function() {
debugger;
};
}
Try adding a statement that uses $scope in $scope.open. Chrome has probably optimized $scope away when you're in $scope.open because you're not using it.
$scope.open = function() {
console.log($scope);
debugger; //now you should see $scope.
};
its worked for me
var app = angular.module("moduleTest",[]);
app.directive("testDirective",function(){
return {
restrict: "A",
scope: true,
link: function(scope, element){
//code
//and $scope is scope
}
}
});
This should work:
app.directive('photo', ['$http', 'modal', function($http, modal) {
return {
replace: true,
templateUrl: '/assets/photo.html',
transclude: false,
scope: {
result: '=',
index: '#'
},
controller: function($scope, $http, modal) {
$scope.prev = $scope.index - 1;
$scope.open = function() {
debugger;
};
}
}
}]);
You need to define the $Scope at the top i.e.:
app.directive('photo', ['$http', '$Scope','modal', function($http, $Scope, modal)
It will work fine now.
I'm trying to get a directive to work with its own controller:
http://jsfiddle.net/edwardtanguay/xfbgjun5/14/
However, when I click the button:
var template = '<button ng-click="vm.addItem()">add item</button>'+
'<ul><li ng-repeat="item in vm.items">{{item}}</li></ul>';
It tells me that:
Error: vm.add is not a function
even though I define controllerAs and bindToController:
return {
restrict: 'A',
scope: {
datasource: '=',
add: '&'
},
controller: controller,
controllerAs: 'vm',
bindToController: true,
template: template
};
and pass in a scope method from the main controller:
<div item-menu datasource="customers" add="addCustomer()"></div>
Why does it not recognize add as a function on vm?
ADDENDUM: The controller looks like this:
.controller('mainController', function ($scope) {
$scope.customers = ['First','Second','Third'];
$scope.score = 0;
$scope.addCustomer = function() {
$scope.score++;
}
})
You can find the answer to your question in this blog post
If you use Angular 1.3 you need to add to the directive the following line of code:
bindToController: true,
Check the blog post and the code snippets.
When you bind to attributes, you have to bind it to $scope, not the controller.
var controller = function($scope) {
var vm = this;
function init() {
vm.items = angular.copy($scope.datasource);
}
init();
vm.addItem = function() {
$scope.add();
vm.items.push('new one');
}
}
http://jsfiddle.net/xfbgjun5/15/
I have yet another issue with minification. This time it's because of the $scope service passed to the directive's controller. See below code:
angular.module('person.directives').
directive("person", ['$dialog', function($dialog) {
return {
restrict: "E",
templateUrl: "person/views/person.html",
replace: true,
scope: {
myPerson: '='
},
controller: function ($scope)
{
$scope.test = 3;
}
}
}]);
If I comment out the controller part, then it works fine.
As you can see, I've used the array declaration for the directive, so the $dialog service is known to Angular even after minification. But how am I supposed to do it for the $scope service on the controller ?
You need to declare a controller as follows:
controller: ['$scope', function ($scope)
{
$scope.test = 3;
}]
Full example here:
angular.module('person.directives').
directive("person", ['$dialog', function($dialog) {
return {
restrict: "E",
templateUrl: "person/views/person.html",
replace: true,
scope: {
myPerson: '='
},
controller: ['$scope', function ($scope)
{
$scope.test = 3;
}]
}
}]);
A solution provided by #Sam would work to but it would mean exposing directive's controller to the whole application which is unnecessary.
ok, I ended up creating the controller in a separate file :
angular.module('person.controllers').controller('personCtrl', ['$scope', function ($scope) {
$scope.test = 3;
}]);
then in the directive, I assign the controller by name:
controller: 'personCtrl'
Not sure it's the best way. It looks clean though. What do you think ?