AngularJS 通过隔离范围进行基于事件的通信
AngularJS event-based communication through isolate scope
在 AngularJS 中,一个指令如何使用基于事件的通信($emit
、$broadcast
和 $on
)与另一个具有隔离作用域的指令通信?我创建了两个指令,当从第二个指令中删除隔离作用域时,第一个指令能够使用 emit 成功地与第二个指令通信。但是,当将隔离范围添加回第二个时,通信中断。
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';
}
};
});
我创建了一个 Plunker 来说明这个问题。你会注意到,如果你在第二个指令的指令定义对象中注释掉 "scope" 属性,通信就可以工作:你可以在第一个指令的输入框中键入一个字符串,按下第一个指令的按钮,字符串被传送到第二个指令,第二个指令将它显示在视图上。 (就目前而言,由于隔离范围问题,Plunker 已损坏,请参阅 app.js 文件的第 19 行。)
http://plnkr.co/edit/AXUVX9zdJx1tApDhgH32
这是我的总体目标:我为第二个指令使用隔离作用域的原因是将内部作用域与外部作用域分开。 (在我的项目中使用的实际 "second directive" 比这个玩具示例复杂得多。这就是它的必要性。)我知道 AngularJS 提供了将外部范围映射到指令内部范围的机制。我很好奇这些机制中的任何一个是否对映射基于事件的通信的事件有用。
如果答案是隔离范围对于基于事件的通信来说是无法克服的,那么在我所说明的情况下完成指令到指令通信的最佳方式是什么,同时仍然实现我的目标?谢谢!
这来自两个问题。
1) 第一个是因为两个指令在 HTML 中处于同一级别,你不能 $emit
从一个范围到另一个范围的事件(除非它们具有相同的范围,即第二个指令没有独立作用域的情况)。
为了让第一个指令联系第二个,您可以用 $scope.$root.$broadcast
(从根范围向下到它的所有范围)替换 $scope.$emit
(在范围层次结构中向上)子级),或者在你的情况下简单地 $scope.$broadcast
因为这个第一个指令范围实际上是根范围!
2) 第二个问题是您的第二个指令在隔离时不会按原样处理范围内含,因此 DOM 中更深层次定义的 HTML 将不会共享该隔离指令作用域,但上面那个没有定义 data
.
将隔离范围传播到内部 HTML 的方法是在 link
函数中使用此代码段:
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone) {
element.append(clone);
});
}
这是一个包含两个修复程序的工作 Plnker:
在 AngularJS 中,一个指令如何使用基于事件的通信($emit
、$broadcast
和 $on
)与另一个具有隔离作用域的指令通信?我创建了两个指令,当从第二个指令中删除隔离作用域时,第一个指令能够使用 emit 成功地与第二个指令通信。但是,当将隔离范围添加回第二个时,通信中断。
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';
}
};
});
我创建了一个 Plunker 来说明这个问题。你会注意到,如果你在第二个指令的指令定义对象中注释掉 "scope" 属性,通信就可以工作:你可以在第一个指令的输入框中键入一个字符串,按下第一个指令的按钮,字符串被传送到第二个指令,第二个指令将它显示在视图上。 (就目前而言,由于隔离范围问题,Plunker 已损坏,请参阅 app.js 文件的第 19 行。)
http://plnkr.co/edit/AXUVX9zdJx1tApDhgH32
这是我的总体目标:我为第二个指令使用隔离作用域的原因是将内部作用域与外部作用域分开。 (在我的项目中使用的实际 "second directive" 比这个玩具示例复杂得多。这就是它的必要性。)我知道 AngularJS 提供了将外部范围映射到指令内部范围的机制。我很好奇这些机制中的任何一个是否对映射基于事件的通信的事件有用。
如果答案是隔离范围对于基于事件的通信来说是无法克服的,那么在我所说明的情况下完成指令到指令通信的最佳方式是什么,同时仍然实现我的目标?谢谢!
这来自两个问题。
1) 第一个是因为两个指令在 HTML 中处于同一级别,你不能 $emit
从一个范围到另一个范围的事件(除非它们具有相同的范围,即第二个指令没有独立作用域的情况)。
为了让第一个指令联系第二个,您可以用 $scope.$root.$broadcast
(从根范围向下到它的所有范围)替换 $scope.$emit
(在范围层次结构中向上)子级),或者在你的情况下简单地 $scope.$broadcast
因为这个第一个指令范围实际上是根范围!
2) 第二个问题是您的第二个指令在隔离时不会按原样处理范围内含,因此 DOM 中更深层次定义的 HTML 将不会共享该隔离指令作用域,但上面那个没有定义 data
.
将隔离范围传播到内部 HTML 的方法是在 link
函数中使用此代码段:
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone) {
element.append(clone);
});
}
这是一个包含两个修复程序的工作 Plnker: