问题
In AngularJS, how can one directive use event-based communication ($emit
, $broadcast
and $on
) to communicate with another directive which has an isolate scope? I've created two directives, and when the isolate scope is removed from the second directive, the first directive is able to use emit to successfully communicate with the second. However, when the isolate scope is added back to the second, communication breaks down.
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've created a Plunker to illustrate the issue. You'll notice that if you comment out the "scope" property in the directive definition object of the second directive, communication works: You're able to type a string into the input box of the first directive, press the button of the first directive, and the string is communicated to the second directive, which displays it on the view. (As it stands, the Plunker is broken, because of the isolate scope issue, see line 19 of the app.js file.)
http://plnkr.co/edit/AXUVX9zdJx1tApDhgH32
Here's my overarching goal: The reason I'm using an isolate scope for the second directive is to separate the scope inside from the scope outside. (The actual "second directive" used in my project is much more complex than this toy example. That's what makes this necessary.) I know AngularJS provides mechanisms for the mapping of the outer scope to a directive's inner scope. I'm curious if any of these mechanisms are useful for mapping the events of event-based communication.
If the answer turns out to be that an isolate scope is insurmountable for event-based communication, what's the best way to accomplish directive to directive communication in the case which I've illustrated, while still accomplishing my goals? Thank you!
回答1:
This comes from two problems.
1) This first one is since both directives are on the same level in HTML, you cannot $emit
an event from one scope to another (unless they have the same scope, which is the case when the second directive doesn't have an isolated scope).
In order for the first directive to contact the second, you can replace $scope.$emit
(which goes upward in the scopes hierarchy) by $scope.$root.$broadcast
(which goes downward from the root scope to all its children), or simply $scope.$broadcast
in your case as this first directive scope is in fact the root scope!
2) The second problem is that your second directive, when isolated, doesn't handle scope transclusion as is, so the HTML defined deeper in the DOM will not share that directive isolated scope, but the one above, which doesn't define data
.
The way to propagate an isolated scope to the inner HTML is by using this snippet within the link
function:
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone) {
element.append(clone);
});
}
here is a working Plnker with both fixes:
http://plnkr.co/edit/I9Vmutal2gfqyLIU0iAe?p=preview
来源:https://stackoverflow.com/questions/30112969/angularjs-event-based-communication-through-isolate-scope