How do I access a controller require'd from another controller?
I have an Angular 1.3 module that looks something like this (directive that requires a parent directive using controllerAs
):
angular.module('fooModule', [])
.controller('FooController', function ($scope) {
this.doSomething = function () {
// Accessing parentDirectiveCtrl via $scope
$scope.parentDirectiveCtrl();
};
})
.directive('fooDirective', function () {
return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, parentDirectiveCtrl) {
scope.parentDirectiveCtrl = parentDirectiveCtrl;
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'
};
});
Here I am just using $scope
to go through parentDirectiveCtrl
, which seems a little awkward.
Is there any other way to access the require
-ed controller from a directive controller without a bind function?
source to share
You should use a function link
to get the require
-ed controllers , but you don't need to use scope to pass the controller reference to its place. Instead, pass it directly to your controller:
.directive('fooDirective', function () {
return {
require: ["fooDirective", "^parentDirective"],
link: function link(scope, element, attrs, ctrls) {
var me = ctrls[0],
parent = ctrls[1];
me.parent = parent;
},
controller: function(){...},
};
});
Be careful, because the controller is working to link, so the controller in this.parent
there undefined
until the communication function is started. If you need to know exactly when this will happen, you can always use a controller function to pass the controller parentDirective
:
link: function link(scope, element, attrs, ctrls) {
//...
me.registerParent(parent);
},
controller: function(){
this.registerParent = function(parent){
//...
}
}
source to share
There is a way to avoid being used $scope
to access the parent controller, but you must use a function link
. Angular documentation says :
Require
Require another directive and inject its controller as the fourth argument to the bind function ...
Option 1
Since it controllerAs
creates a namespace in scope
your controller, you can access that namespace inside your function link
and place the required controller directly on the controller childDirective
instead of using it $scope
. Then the code will look like this.
angular.module('app', []).
controller('parentController', function() {
this.doSomething = function() {
alert('parent');
};
}).
controller('childController', function() {
this.click = function() {
this.parentDirectiveCtrl.doSomething();
}
}).
directive('parentDirective', function() {
return {
controller: 'parentController'
}
}).
directive('childDirective', function() {
return {
template: '<button ng-click="controller.click()">Click me</button>',
link: function link(scope, element, attrs, parentDirectiveCtrl) {
scope.controller.parentDirectiveCtrl = parentDirectiveCtrl;
},
controller: 'childController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'
}
});
Plunker
http://plnkr.co/edit/YwakJATaeuvUV2RBDTGr?p=preview
Option 2
I usually don't use controllers at all in my directives and can't use functions through services. If you don't need to mess with the isolated scopes of parent and child directives, just add the same service to both of them and enable all functionality.
angular.module('app', []).
service('srv', function() {
this.value = '';
this.doSomething = function(source) {
this.value = source;
}
}).
directive('parentDirective', ['srv', function(srv) {
return {
template: '<div>' +
'<span ng-click="srv.doSomething(\'parent\')">Parent {{srv.value}}</span>' +
'<span ng-transclude></span>' +
'</div>',
transclude: true,
link: function(scope) { scope.srv = srv; }
};
}]).
directive('childDirective', ['srv', function(srv) {
return {
template: '<button ng-click="srv.doSomething(\'child\')">Click me</button>',
link: function link(scope) { scope.srv = srv; }
}
}]);
Plunker
source to share
Good question! Angular allows you to pass in a "parent" controller. You already have a parameter in your link function. This is the fourth parameter. I named it ctrl for simplicity. You don't need the line scope.parentDirectiveCtrl = parentDirectiveCtrl that you have.
.directive('fooDirective', function () {
return {
// Passing in parentDirectiveCtrl into $scope here
link: function link(scope, element, attrs, ctrl) {
// What you had here is not required.
},
controller: 'FooController',
controllerAs: 'controller',
bindToController: true,
require: '^parentDirective'};});
Now your parent controller has
this.doSomething=function().
You can access this doSomething as
ctrl.doSomething().
source to share