【问题标题】:Communication between nested directives嵌套指令之间的通信
【发布时间】:2014-05-19 08:54:14
【问题描述】:

我正在尝试在父指令与其嵌套的子指令之间进行通信,反之亦然。我已经设法通过使用 $broadcast 和 $emit 来实现这一点,但是因为我将一些参数传递给指令,所以我必须在我的指令上创建隔离范围,所以为了让 $broadcast/$emit工作我必须在父范围(scope.$parent.$broadcast)上广播“上一级”。 现在广播不再只是去嵌套的孩子,而是去同一级别的所有指令,这是我不想要的。我创建了一个 plunker 来显示这个问题,here。 我需要的是当按下其中一个按钮时,只有子指令接收广播消息,反之亦然。我是否遗漏了什么,或者在使用隔离范围时这是不可能的?

在我的 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');
      });
    }
  }
});

【问题讨论】:

  • 谢谢,但我认为这些都不适用;我不想注入服务(似乎矫枉过正)。要求父指令不起作用(我假设是因为使用了 transclude),并且在父作用域中执行表达式(通过 &)会起作用,但只有一种方式(嵌套指令在父指令上执行函数)。
  • 您是否考虑为指令设置 id,然后只有与外部指令具有相同 id 的内部指令才能处理事件。看看这个例子plnkr.co/edit/dqGPDMF3f8NLBH4GX6dO?p=preview
  • 是的,这实际上是我当前的实现/解决方法,正在使用您在 plunker 中显示的“id”。它有效,但感觉不...'正确'!如果有更清洁的方法,我只是在徘徊,但至少这是一个可行的选择!

标签: angularjs angularjs-directive angularjs-scope


【解决方案1】:

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

1) 公共服务。

这对您来说不是一个好的解决方案,因为服务始终是单例的,并且您希望拥有多个唯一的指令。如果您在服务中维护了父母和孩子的字典并管理将呼叫路由到正确的关联父母/孩子,您只能使用服务,这与您使用事件时遇到的问题相同。

2) 事件。

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

3) 单向绑定。

隔离作用域中的“&”绑定允许您将父函数传递给子函数。然后子级可以在父级范围上调用这些函数来通知父级更改。这对于孩子与父母的交流非常有用,但不会反过来。您可以将此解决方案与广播来自父母的事件结合起来与孩子交流。

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);
    }
  }
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-05
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多