Originally sourced from here, but seeking more tailored responses here!
When dealing with nested directives, the need for communication between them arises. For example, inner directives may need to inform the outer directive about certain user choices.
<outer>
<inner></inner>
<inner></inner>
</outer>
Here are five approaches I've identified so far:
Using 'require' in conjunction with parent directive
The inner directive can require the outer directive and access a method exposed by its controller. In the definition of the inner directive:
require: '^outer',
link: function(scope, iElement, iAttrs, outerController) {
// This method can be invoked in the template using ng-click
$scope.chosen = function() {
outerController.chosen(something);
}
}
The outer directive’s controller would look something like this:
controller: function($scope) {
this.chosen = function(something) {
}
}
Utilizing $emit events
The inner directive can use $emit to trigger an event that the outer directive responds to with $on. Within the inner directive's controller:
controller: function($scope) {
$scope.chosen = function() {
$scope.$emit('inner::chosen', something);
}
}
And within the outer directive's controller:
controller: function($scope) {
$scope.$on('inner::chosen, function(e, data) {
}
}
Execution of expression in parent scope via &
An item can bind to an expression in the parent scope and execute it when appropriate. The HTML structure might look like this:
<outer>
<inner inner-choose="functionOnOuter(item)"></inner>
<inner inner-choose="functionOnOuter(item)"></inner>
</outer>
In the inner controller, there would be an 'innerChoose' function that could be called:
scope: {
'innerChoose': '&'
},
controller: function() {
$scope.click = function() {
$scope.innerChoose({item:something});
}
}
This would then trigger the 'functionOnOuter' function on the outer directive's scope:
controller: function($scope) {
$scope.functionOnOuter = function(item) {
}
}
Scope inheritance on non-isolated scopes
Since these are nested controllers, scope inheritance allows the inner directive to call functions in the scope chain (as long as it doesn’t have an isolated scope). 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) {
}
}
By injecting a service into both inner and outer directives
A shared service can be injected into both directives, allowing them direct access to the same object or the ability to notify the service of actions. They could even register themselves for notifications in a pub/sub system, without the need for nesting.
Question: What are the potential advantages and drawbacks of each approach compared to the others?