Reputation: 525
There seem to be quite a few ways of communicating between directives. Say you have nested directives, where the inner directives must communicate something to the outer (e.g. it's been chosen by the user).
<outer>
<inner></inner>
<inner></inner>
</outer>
So far I have 5 ways of doing this
require:
parent directiveThe inner
directive can require the outer
directive, which can expose some method on its controller. So in the inner
definition
require: '^outer',
link: function(scope, iElement, iAttrs, outerController) {
// This can be passed to ng-click in the template
$scope.chosen = function() {
outerController.chosen(something);
}
}
And in the outer
directive's controller:
controller: function($scope) {
this.chosen = function(something) {
}
}
$emit
eventThe inner
directive can $emit
an event, which the outer
directive can respond to, via $on
. So in the inner
directive's controller:
controller: function($scope) {
$scope.chosen = function() {
$scope.$emit('inner::chosen', something);
}
}
and in the outer
directives controller:
controller: function($scope) {
$scope.$on('inner::chosen, function(e, data) {
}
}
&
The item can bind to an expression in the parent scope, and execute it at an appropriate point. The HTML would be like:
<outer>
<inner inner-choose="functionOnOuter(item)"></inner>
<inner inner-choose="functionOnOuter(item)"></inner>
</outer>
So the inner
controller has an 'innerChoose' function it can call
scope: {
'innerChoose': '&'
},
controller: function() {
$scope.click = function() {
$scope.innerChoose({item:something});
}
}
which would call (in this case) the 'functionOnOuter' function on the outer
directive's scope:
controller: function($scope) {
$scope.functionOnOuter = function(item) {
}
}
Given that these are nested controllers, scope inheritance can be at work, and the inner directive can just call any functions in the scope chain, as long as it doesn't have an isolated scope). So in the inner
directive:
// scope: anything but a hash {}
controller: function() {
$scope.click = function() {
$scope.functionOnOuter(something);
}
}
And in the outer
directive:
controller: function($scope) {
$scope.functionOnOuter = function(item) {
}
}
A service can be injected into both directives, so they can have direct access to the same object, or call functions to notify the service, and maybe even register themselves to be notified, in a pub/sub system. This doesn't require the directives to be nested.
Question: What are any potential drawbacks and advantages of each over the others?
Credit/Disclaimer: This is not my question, I found the original question on programmers.The original author never moved it over here as suggested.
Upvotes: 1
Views: 167
Reputation: 9486
Just want to point another way for directive to interact - via objects:
<outer model='model'>
<inner model='model[0]'></inner>
<inner model='model[1]'></inner>
</outer>
Or more familiar case:
<input type="checkbox" ng-model="smth"/>
<div ng-show="smth"></div>
Upvotes: 0
Reputation: 19193
Thanks for pointing out to the original author.
Here are when I think each situation should be preffered:
require
parent directive if&
ifNah, don't. It is same as using require
except you don't guarantee inner will be inside outer, and it become very unclear for a programmer how to use that directive.
$emit
caseThat's about it. A service is always better than a broadcast because it explicitely tell the programmer which events have an effect on the directive. Using $emit
and the like is really the wrost option most of the time, as it all behave like the old school goto
expression that many developpers love to hate: you'll have a bad time trying to debug your directives when you have too many events.
Now if the hierarchy is guaranteed and the API fixed I recommend using require
as it becomes one less worry for the developper using the directives.
Upvotes: 2