自定义 Angular 指令广播事件但不广播给嵌套子项?
Custom Angular directive broadcasting an event but not to nested children?
我在 Angular 中创建了一个可以嵌套的手风琴指令,因此手风琴可以在其中包含子手风琴。
我想在手风琴打开和关闭时传播一个事件,以便其他指令可以侦听它(例如,手风琴面板内的菜单可能会在其内部的手风琴打开时自行显示)。
问题是,如果在外部手风琴内部有嵌套的内部手风琴,我不希望将事件广播到内部手风琴的子元素,因为内部手风琴没有广播 open/close事件。
以防万一没有意义,换句话说,嵌套手风琴中的元素应该能够收听它所在的手风琴广播的 open/close 事件,而不是更上层的手风琴DOM 树。
希望有一个简单的解决方案。
更新: 在此处添加演示:http://jsfiddle.net/jonhobbs/xr1kLqba/
我显然没有正确理解 $broadcast 和 $on,因为演示活动目前根本无法正常工作,但应该清楚我要做什么!
编辑: 显然所有指向 jsfiddle 的链接都必须附有代码,所以这里有一些。
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.mainMenuOpen = true;
})
.directive('myPanel', function() {
return {
restrict: 'EA',
scope: {
isOpen: '=?'
},
link: function($scope, $element, $attrs) {
$element.find('> BUTTON').bind('click', function() {
$scope.isOpen = !$scope.isOpen;
if ($scope.isOpen) {
$scope.$broadcast('panelOpened');
}
});
}
};
})
.directive('reactToPanelOpenClose', function() {
return {
restrict: 'EA',
scope: {},
link: function($scope, $element, $attrs) {
$scope.$on('panelOpened', function() {
alert("clicked");
$element.css({ 'background-color': 'red' });
});
}
};
});
您可以添加一个数字值 depth
或类似于您的广播,它定义了发送广播的层级深度。如果指令控制器侦听的 depth
高于 1
,则它可以执行。否则它可以忽略广播。
如果不清楚,我也可以添加一个小例子,让我知道。
到目前为止,最简单的方法是使用您在评论中提到的 require
。
解决这个问题的一种方法是注册子控制器(或者甚至是它们的回调函数),然后父控制器可以调用每个子控制器而不是广播。
这里要注意的是,您需要 require: "?^^parent"
- 意思是,使 require 成为可选的和严格的祖先选择器;因为 "^"
Angular 会 return 自己。
.directive("accordion", function(){
return {
require: ["accordion", "?^^accordion"],
controller: function(){
var children = [];
this.registerChild = function(childCtrl){
children.push(childCtrl);
}
this.handleNotification = function(){
// do something when notification arrives from parent
}
this.notify = function(){
angular.forEach(children, function(child){
child.handleNotification();
})
}
},
link: function(scope, element, attrs, ctrls){
var me = ctrls[0], parent = ctrls[1];
if (parent){
parent.registerChild(me);
}
}
}
})
你正试图在 jQuery 回调中使用 angular 上下文,所以这是行不通的。解决问题的最简单方法是以下代码片段:
angular.$externalBroadcast = function (element, event, data) {
var scope = element.scope();
scope.$apply(function () {
scope.$broadcast(event, data);
});
};
并在面板指令的 link 函数中应用此函数:
$scope.isOpen = !$scope.isOpen;
if($scope.isOpen){
angular.$externalBroadcast($element, 'panelOpened');
}
看看这个修改后的Fiddle。
我在 Angular 中创建了一个可以嵌套的手风琴指令,因此手风琴可以在其中包含子手风琴。
我想在手风琴打开和关闭时传播一个事件,以便其他指令可以侦听它(例如,手风琴面板内的菜单可能会在其内部的手风琴打开时自行显示)。
问题是,如果在外部手风琴内部有嵌套的内部手风琴,我不希望将事件广播到内部手风琴的子元素,因为内部手风琴没有广播 open/close事件。
以防万一没有意义,换句话说,嵌套手风琴中的元素应该能够收听它所在的手风琴广播的 open/close 事件,而不是更上层的手风琴DOM 树。
希望有一个简单的解决方案。
更新: 在此处添加演示:http://jsfiddle.net/jonhobbs/xr1kLqba/
我显然没有正确理解 $broadcast 和 $on,因为演示活动目前根本无法正常工作,但应该清楚我要做什么!
编辑: 显然所有指向 jsfiddle 的链接都必须附有代码,所以这里有一些。
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.mainMenuOpen = true;
})
.directive('myPanel', function() {
return {
restrict: 'EA',
scope: {
isOpen: '=?'
},
link: function($scope, $element, $attrs) {
$element.find('> BUTTON').bind('click', function() {
$scope.isOpen = !$scope.isOpen;
if ($scope.isOpen) {
$scope.$broadcast('panelOpened');
}
});
}
};
})
.directive('reactToPanelOpenClose', function() {
return {
restrict: 'EA',
scope: {},
link: function($scope, $element, $attrs) {
$scope.$on('panelOpened', function() {
alert("clicked");
$element.css({ 'background-color': 'red' });
});
}
};
});
您可以添加一个数字值 depth
或类似于您的广播,它定义了发送广播的层级深度。如果指令控制器侦听的 depth
高于 1
,则它可以执行。否则它可以忽略广播。
如果不清楚,我也可以添加一个小例子,让我知道。
到目前为止,最简单的方法是使用您在评论中提到的 require
。
解决这个问题的一种方法是注册子控制器(或者甚至是它们的回调函数),然后父控制器可以调用每个子控制器而不是广播。
这里要注意的是,您需要 require: "?^^parent"
- 意思是,使 require 成为可选的和严格的祖先选择器;因为 "^"
Angular 会 return 自己。
.directive("accordion", function(){
return {
require: ["accordion", "?^^accordion"],
controller: function(){
var children = [];
this.registerChild = function(childCtrl){
children.push(childCtrl);
}
this.handleNotification = function(){
// do something when notification arrives from parent
}
this.notify = function(){
angular.forEach(children, function(child){
child.handleNotification();
})
}
},
link: function(scope, element, attrs, ctrls){
var me = ctrls[0], parent = ctrls[1];
if (parent){
parent.registerChild(me);
}
}
}
})
你正试图在 jQuery 回调中使用 angular 上下文,所以这是行不通的。解决问题的最简单方法是以下代码片段:
angular.$externalBroadcast = function (element, event, data) {
var scope = element.scope();
scope.$apply(function () {
scope.$broadcast(event, data);
});
};
并在面板指令的 link 函数中应用此函数:
$scope.isOpen = !$scope.isOpen;
if($scope.isOpen){
angular.$externalBroadcast($element, 'panelOpened');
}
看看这个修改后的Fiddle。