How to require a controller in an angularjs directive
Solution 1
I got lucky and answered this in a comment to the question, but I'm posting a full answer for the sake of completeness and so we can mark this question as "Answered".
It depends on what you want to accomplish by sharing a controller; you can either share the same controller (though have different instances), or you can share the same controller instance.
Share a Controller
Two directives can use the same controller by passing the same method to two directives, like so:
app.controller( 'MyCtrl', function ( $scope ) {
// do stuff...
});
app.directive( 'directiveOne', function () {
return {
controller: 'MyCtrl'
};
});
app.directive( 'directiveTwo', function () {
return {
controller: 'MyCtrl'
};
});
Each directive will get its own instance of the controller, but this allows you to share the logic between as many components as you want.
Require a Controller
If you want to share the same instance of a controller, then you use require
.
require
ensures the presence of another directive and then includes its controller as a parameter to the link function. So if you have two directives on one element, your directive can require the presence of the other directive and gain access to its controller methods. A common use case for this is to require ngModel
.
^require
, with the addition of the caret, checks elements above directive in addition to the current element to try to find the other directive. This allows you to create complex components where "sub-components" can communicate with the parent component through its controller to great effect. Examples could include tabs, where each pane can communicate with the overall tabs to handle switching; an accordion set could ensure only one is open at a time; etc.
In either event, you have to use the two directives together for this to work. require
is a way of communicating between components.
Check out the Guide page of directives for more info: http://docs.angularjs.org/guide/directive
Solution 2
There is a good stackoverflow answer here by Mark Rajcok:
AngularJS directive controllers requiring parent directive controllers?
with a link to this very clear jsFiddle: http://jsfiddle.net/mrajcok/StXFK/
<div ng-controller="MyCtrl">
<div screen>
<div component>
<div widget>
<button ng-click="widgetIt()">Woo Hoo</button>
</div>
</div>
</div>
</div>
JavaScript
var myApp = angular.module('myApp',[])
.directive('screen', function() {
return {
scope: true,
controller: function() {
this.doSomethingScreeny = function() {
alert("screeny!");
}
}
}
})
.directive('component', function() {
return {
scope: true,
require: '^screen',
controller: function($scope) {
this.componentFunction = function() {
$scope.screenCtrl.doSomethingScreeny();
}
},
link: function(scope, element, attrs, screenCtrl) {
scope.screenCtrl = screenCtrl
}
}
})
.directive('widget', function() {
return {
scope: true,
require: "^component",
link: function(scope, element, attrs, componentCtrl) {
scope.widgetIt = function() {
componentCtrl.componentFunction();
};
}
}
})
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
}
Subtubes
Updated on April 19, 2020Comments
-
Subtubes about 4 years
Can anyone tell me how to include a controller from one directive in another angularJS directive. for example I have the following code
var app = angular.module('shop', []). config(['$routeProvider', function ($routeProvider) { $routeProvider.when('/', { templateUrl: '/js/partials/home.html' }) .when('/products', { controller: 'ProductsController', templateUrl: '/js/partials/products.html' }) .when('/products/:productId', { controller: 'ProductController', templateUrl: '/js/partials/product.html' }); }]); app.directive('mainCtrl', function () { return { controller: function ($scope) {} }; }); app.directive('addProduct', function () { return { restrict: 'C', require: '^mainCtrl', link: function (scope, lElement, attrs, mainCtrl) { //console.log(cartController); } }; });
By all account I should be able to access the controller in the addProduct directive but I am not. Is there a better way of doing this?
-
CMCDragonkai almost 11 yearsIs it possible to require a sibling directive controller? Basically I need to share the same instance of a controller or service between sibling directives (as in DOM siblings, not on the same DOM element) that is repeated using ng-repeat. Imagine each repeated item has a directive that needs a shared state or logic between them.
-
Josh David Miller almost 11 years@CMCDragonkai There's no way to do that, but there are two common ways of accomplishing the same thing. The first is if the siblings are all of the same "type" then the element above the ngRepeat can be like a container directive and all the sub-elements can then require that directive instead, all sharing the same controller. The more common solution - and often more canonical - is to use a shared service. Can you elaborate on what these siblings do and what they need to share?
-
CMCDragonkai almost 11 yearsYep ended up doing the first option. Using a container directive controller. Works great. It's for Masonry.
-
coblr over 10 yearsFor me, what made Mark Rajcok's example click the most was paying attention to how the controller methods are created. Typically you see controller methods created via $scope.methodName = function(){...}, but in order for this to work, you must use this.methodName for the methods you want accessible. I didn't notice that at first.
-
jedd.ahyoung over 9 yearsThis is a great answer and has solidified my understanding of how all of this works. Thanks! (As a note, this may be a newer feature, but you can use
require
to specify a single directive, or an array of directives; each directive can be prefixed with a caret(^
) for more granular requirements.) -
jsbisht over 8 yearsUsing same controller in two directives does not give each directive it's own instance.