AngularJS基于事件的通信通过隔离范围

时间:2021-08-07 19:35:55

In AngularJS, how can one directive use event-based communication ($emit, $broadcast and $on) to communicate with another directive which has an isolate scope? I've created two directives, and when the isolate scope is removed from the second directive, the first directive is able to use emit to successfully communicate with the second. However, when the isolate scope is added back to the second, communication breaks down.

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

I've created a Plunker to illustrate the issue. You'll notice that if you comment out the "scope" property in the directive definition object of the second directive, communication works: You're able to type a string into the input box of the first directive, press the button of the first directive, and the string is communicated to the second directive, which displays it on the view. (As it stands, the Plunker is broken, because of the isolate scope issue, see line 19 of the app.js file.)

我创建了一个Plunker来说明问题。您会注意到,如果您在第二个指令的指令定义对象中注释掉“scope”属性,则通信可以正常工作:您可以在第一个指令的输入框中键入一个字符串,按下第一个指令的按钮指令,并将字符串传递给第二个指令,该指令将其显示在视图上。 (就目前而言,由于隔离范围问题,Plunker已损坏,请参阅app.js文件的第19行。)

http://plnkr.co/edit/AXUVX9zdJx1tApDhgH32

Here's my overarching goal: The reason I'm using an isolate scope for the second directive is to separate the scope inside from the scope outside. (The actual "second directive" used in my project is much more complex than this toy example. That's what makes this necessary.) I know AngularJS provides mechanisms for the mapping of the outer scope to a directive's inner scope. I'm curious if any of these mechanisms are useful for mapping the events of event-based communication.

这是我的首要目标:我为第二个指令使用隔离范围的原因是将范围内部与范围外部区分开来。 (我的项目中使用的实际“第二指令”比这个玩具示例复杂得多。这就是必要的。)我知道AngularJS提供了将外部范围映射到指令内部范围的机制。我很好奇这些机制中的任何一个对于映射基于事件的通信事件是否有用。

If the answer turns out to be that an isolate scope is insurmountable for event-based communication, what's the best way to accomplish directive to directive communication in the case which I've illustrated, while still accomplishing my goals? Thank you!

如果答案结果证明隔离范围对于基于事件的通信是不可克服的,那么在我已经说明的情况下,在完成目标的同时完成指令通信指令的最佳方法是什么?谢谢!

1 个解决方案

#1


This comes from two problems.

这来自两个问题。

1) This first one is since both directives are on the same level in HTML, you cannot $emit an event from one scope to another (unless they have the same scope, which is the case when the second directive doesn't have an isolated scope).

1)第一个是因为两个指令在HTML中处于同一级别,你不能$从一个范围发出一个事件到另一个范围(除非它们具有相同的范围,这是第二个指令没有孤立的情况)范围)。

In order for the first directive to contact the second, you can replace $scope.$emit (which goes upward in the scopes hierarchy) by $scope.$root.$broadcast (which goes downward from the root scope to all its children), or simply $scope.$broadcast in your case as this first directive scope is in fact the root scope!

为了使第一个指令与第二个指令联系,你可以用$ scope替换$ scope。$ emit(在作用域层次结构中向上)。$ root。$ broadcast(从根作用域向下移动到它的所有子作用域)或者只是$ scope。$在你的情况下广播,因为这个第一个指令范围实际上是根范围!

2) The second problem is that your second directive, when isolated, doesn't handle scope transclusion as is, so the HTML defined deeper in the DOM will not share that directive isolated scope, but the one above, which doesn't define data.

2)第二个问题是你的第二个指令在被隔离时不会按原样处理范围转换,因此在DOM中更深层次定义的HTML将不会共享该指令隔离范围,而是上面的那个,它没有定义数据。

The way to propagate an isolated scope to the inner HTML is by using this snippet within the link function:

将隔离范围传播到内部HTML的方法是在链接函数中使用此代码段:

link: function(scope, element, attrs, ctrl, transclude) {
  transclude(scope, function(clone) {
    element.append(clone);
  });
}

here is a working Plnker with both fixes:

这是一个工作的Plnker,有两个修复:

http://plnkr.co/edit/I9Vmutal2gfqyLIU0iAe?p=preview

#1


This comes from two problems.

这来自两个问题。

1) This first one is since both directives are on the same level in HTML, you cannot $emit an event from one scope to another (unless they have the same scope, which is the case when the second directive doesn't have an isolated scope).

1)第一个是因为两个指令在HTML中处于同一级别,你不能$从一个范围发出一个事件到另一个范围(除非它们具有相同的范围,这是第二个指令没有孤立的情况)范围)。

In order for the first directive to contact the second, you can replace $scope.$emit (which goes upward in the scopes hierarchy) by $scope.$root.$broadcast (which goes downward from the root scope to all its children), or simply $scope.$broadcast in your case as this first directive scope is in fact the root scope!

为了使第一个指令与第二个指令联系,你可以用$ scope替换$ scope。$ emit(在作用域层次结构中向上)。$ root。$ broadcast(从根作用域向下移动到它的所有子作用域)或者只是$ scope。$在你的情况下广播,因为这个第一个指令范围实际上是根范围!

2) The second problem is that your second directive, when isolated, doesn't handle scope transclusion as is, so the HTML defined deeper in the DOM will not share that directive isolated scope, but the one above, which doesn't define data.

2)第二个问题是你的第二个指令在被隔离时不会按原样处理范围转换,因此在DOM中更深层次定义的HTML将不会共享该指令隔离范围,而是上面的那个,它没有定义数据。

The way to propagate an isolated scope to the inner HTML is by using this snippet within the link function:

将隔离范围传播到内部HTML的方法是在链接函数中使用此代码段:

link: function(scope, element, attrs, ctrl, transclude) {
  transclude(scope, function(clone) {
    element.append(clone);
  });
}

here is a working Plnker with both fixes:

这是一个工作的Plnker,有两个修复:

http://plnkr.co/edit/I9Vmutal2gfqyLIU0iAe?p=preview