AngularJS event communication via isolation
In AngularJS, how can one directive use event-based communication ( $emit
, $broadcast
and $on
) to communicate with another directive that has a scoping? I created two directives and when the scoping is removed from the second directive, the first directive can use emit to communicate successfully with the second. However, when a selection area is added to the second, the link is broken.
var app = angular.module('myApp', []);
app.directive("firstDir", function() {
return {
restrict: 'E',
controller: function($scope) {
$scope.set = function() {
$scope.$emit('MY_NEW_SEARCH', $scope.searchQuery);
}
},
template: '<input type="text" ng-model="searchQuery"><button ng-click="set()">Change Value</button>'
};
});
app.directive("secondDir", function() {
return {
restrict : 'E',
scope: {},
controller : function($scope) {
var _that = $scope;
$scope.$on('MY_NEW_SEARCH', function(e, data) {
_that.data = data;
});
$scope.data = 'init value';
}
};
});
I created Plunker to illustrate the problem. You will notice that if you comment out the "scope" property in the directive definition object of the second directive, the linking works: you can enter a string in the input field of the first directive, click the button of the first, and the string is passed to the second directive, which displays it on the view. (Since this means Plunker is broken, due to a marquee issue, see line 19 of the app.js.)
http://plnkr.co/edit/AXUVX9zdJx1tApDhgH32
Here's my main goal: The reason I'm using the marquee for the second directive is to separate the region inside from the outside. (The actual "second directive" used in my project is much more complex than this toy example. This makes it necessary.) I know that AngularJS provides mechanisms for mapping the outer scope to the directive inner scope. I am wondering if any of these mechanisms are useful for event-based communication events mapping.
If the answer turns out to be that the isolation area is insurmountable for event-based communication, what is the best way to fulfill the directive for directive communication in the case I have illustrated, but still fulfill my goals? Thank!
source to share
This is due to two problems.
1) This is the first, since both directives are at the same level in HTML, you cannot $emit
event from one scope to another (unless they have the same scope as in the case where the second directive does not matter, t have an insulated volume).
To get the first directive to bind to the second, you can replace $scope.$emit
(which goes up in the scope hierarchy) with $scope.$root.$broadcast
(which goes down from the root scope to all of its children) or just $scope.$broadcast
in your case, since that first scope is actually the root scope!
2) The second problem is that your second directive, when isolated, does not handle translation as it is, so HTML defined deeper into the DOM will not separate that directive isolated scope, but above, t define data
.
The way to propagate an isolated area into inner HTML is to use this snippet inside a function link
:
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone) {
element.append(clone);
});
}
Plnker works here with two fixes:
source to share