嵌套指令之间的通信

时间:2014-04-07 08:12:31

标签: angularjs angularjs-directive angularjs-scope

我正在尝试在父指令和它的嵌套子指令之间进行通信,反之亦然。我已经设法通过使用$ broadcast和$ emit来实现这一点,但是因为我在指令中传递了一些参数,我必须在我的指令上创建隔离范围,所以为了$ broadcast / $ emit来我必须在父作用域(范围。$ parent。$ broadcast)上播放'up a level'。 现在,广播不再仅仅是针对嵌套子节点,而是针对同级别的所有指令,这是我不想要的。我已经创建了一个用于显示问题的plunker here。 我需要的是当按下其中一个按钮时,只有child指令接收广播消息,反之亦然。我错过了什么,或者在使用隔离范围时这是不可能的?

在我的HTML中:

<body ng-app="myApp">
  <directive1 data-title="Click me to change name">
    <directive2 data-name="John Smith"></directive2>
  </directive1>

  <directive1 data-title="Click me to change this other name">
    <directive2 data-name="Gordon Freeman"></directive2>
  </directive1>
</body>

指令1:

<div>
  <button ng-click="changeName()">{{title}}</button>
  <div ng-transclude></div>
</div>

指令2:

<div>
  <h2>{{name}}</h2>
</div>

我的指示:

myApp.directive('directive1', function(){
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'Directive1.html',
    transclude: true,
    scope: {
      title: '@'
    },
    link: function(scope, elem){
      scope.changeName = function() {
        scope.$parent.$broadcast('ChangeName');
      };

      scope.$parent.$on('NameChanged', function(event, args){
        scope.title = 'Name changed to ' + args;
      });
    }
  }
});


myApp.directive('directive2', function(){
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'Directive2.html',
    scope: {
      name: '@'
    },
    link: function(scope, elem){
      scope.$on('ChangeName', function(event, args){
        scope.name = 'Adam West';

        scope.$emit('NameChanged', 'Adam West');
      });
    }
  }
});

1 个答案:

答案 0 :(得分:4)

指令之间有5种主要的沟通方式:

1)一项普通服务。

这对您来说不是一个好的解决方案,因为服务总是单例,并且您希望拥有多个唯一的指令。如果您在服务中维护父母和子女的字典并且管理路由调用右侧关联的父/子,那么您只能使用服务,这与您使用事件的问题相同。

2)活动。

如果您无法通过右侧节点广播将事件限制在DOM /树的正确部分,则必须为事件添加唯一标识符。在这种情况下,如果您正在从根广播和/或多个孩子正在接收消息,请为每个父/子提供唯一标识符并将其添加到emit / broadcast / on。这不是一个很好的解决方案,但它会起作用。

3)单向绑定。

'&amp;'在隔离范围内绑定允许您将父函数传递给子级。然后,子进程可以在父作用域上调用这些函数,以通知父进程发生更改。这对于孩子 - 父母的沟通非常有用,但不会反过来。您可以将此解决方案与来自父母的广播事件相结合,以便与孩子进行沟通。

4)双向绑定。

有时,您可以使用隔离范围上的属性将信息或标志传回,并传递给父子。这在你的例子中不起作用,因为父母对他的孩子一无所知,因为孩子是通过翻译注射的。

5)require家长控制器。

指令可以使用require属性指定另一个指令要么作为父指令存在,要么存在于同一元素上。你不能要求兄弟指令。必需的指令必须定义控制器。然后将控制器传递给链接(或编译)功能,您可以在控制器上调用函数。这可用于允许指令之间的通信。在您的示例中,如果directive2需要directive1,您可以将addChild()之类的函数设置到控制器。然后,子(directive2)将自己添加到可以在调用changeName时更新/调用所有子项的父项。

myApp.directive('directive1', function(){
  return {
    // ...
    controller: function($scope) {
      $scope.children = [];
      this.addChild = function(child) {
        $scope.children.push(child);
      }
    },
    link: function(scope, elem){
      scope.changeName = function() {
        _.each(scope.children, function(child) {
          child.setName('Adam West');
        };
      };
    },
  }
});


myApp.directive('directive2', function(){
  return {
    // ...
    require: "^directive1", // require directive1 as a parent or on same element
    link: function(scope, elem, attributes, directive1Controller){
      child = {
        setName: function(name) {
          scope.name = name;
        },
      };

      directive1Controller.addChild(child);
    }
  }
});