自定义 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