简体   繁体   English

带有发布/订阅的指令之间的Angularjs事件通信

[英]Angularjs event communication between directives with publish/subscribe

I want to create a publish/subscribe mechanism with angular event system. 我想用角度事件系统创建一个发布/订阅机制。

angular.module("app",[]);

angular.module("app").directive("first", function($rootScope){
        return {
          template: "First Directive",
          link:function(scope,element,attribute){
               $rootScope.$broadcast("OnFirstDirectiveCreated", {
                "message": "I'm first directive"
            });
      }
    }
})

angular.module("app").directive("second", function($rootScope){
        return {
          template: "Second Directive",
          link:function(scope,element,attribute){
            var handler = $rootScope.$on("OnFirstDirectiveCreated", 
                function (event, args) {
                  console.log("First Directive Message: " + args.message);
            });
      }
    }
})

if I set HTML document like this, no message appear in console: 如果我这样设置HTML文档,则控制台中不会显示任何消息:

<div ng-app="app">
  <first></first>
  <second></second>
</div>

If I change order first and second, message wirite on console. 如果我先更改顺序,然后在控制台上写消息。

<div ng-app="app">
  <second></second>
  <first></first>
</div>

But I need first directive or inner directive. 但是我需要第一个指令或内部指令。

<div ng-app="app">
  <first></first>
  <second></second>
</div>

<div ng-app="app">
  <first>
      <second></second>
  </first>
</div>

I tried both $rootScope.$broadcast and $rootScope.$emit but did not woeked. 我尝试了$rootScope.$broadcast$rootScope.$emit但是都没问题。

Working DEMO 工作演示

It's absolutely correct angular behavior. 这是绝对正确的角度行为。

In the first example: 在第一个示例中:

<first></first>
<second></second>

Angular creates a directive for first tag and sends event immediately, but the second directive is not created yet. Angular为first标记创建一个指令并立即发送事件,但尚未创建第二个指令。

In the second example: 在第二个示例中:

<first></first>
<second></second>

Here you firstly subscribe to an event, and after that first directive sends a message. 在这里,您首先订阅一个事件,然后该first指令发送一条消息。 Because of this, second directive accepts an event. 因此, second指令接受一个事件。

Third example: 第三个例子:

<first>
   <second></second>
</first>

This case, as well as the first example won't be working. 这种情况以及第一个示例都行不通。

Solution: One of solutions is to set timeout in first directive to don't send event immediately after creation. 解决方案:解决方案之一是在第一个指令中设置超时,以使其在创建后不立即发送事件。 If the second parameter of $timeout , delay is not provided, the default behaviour is to execute the function after the DOM has completed rendering: 如果不提供$timeout的第二个参数delay ,则默认行为是在DOM完成渲染后执行该函数:

angular.module("app").directive("first", function($rootScope, $timeout) {
  return {
    template: "First Directive",
    link: function(scope,element,attribute) {
      $timeout(function() {
        $rootScope.$broadcast("OnFirstDirectiveCreated", {
          "message": "I'm first directive"
        })
      });
    }
  }
});

Demo 演示版

This happens because when broadcast of first directive is executed, the second directive is not ready and therefore the signal is lost and communication does not happen. 发生这种情况的原因是,当执行第一个指令的广播时,第二个指令未准备好,因此信号丢失并且通信没有发生。 One way of solving it, is to send the signal many times using $interval function and stop transmitting only when the second directive is ready. 解决它的一种方法是使用$ interval函数多次发送信号,并仅在第二条指令就绪时才停止发送信号。 Of course the second directive has to broadcast back when it receives data from the first. 当然,第二个指令从第一个指令接收数据时必须广播回去。 The second solution, for which I would go, is for the second directive to notify when its ready to the first directive by broadcasting with $rootScope in a similar fashion as you did in first directive. 我要讲的第二种解决方案是,第二条指令通过以与您在第一条指令中类似的方式与$ rootScope进行广播,以通知第二条指令何时准备好接收第一条指令。

angular.module("app").directive("second", function($rootScope){
    return {
      template: "Second Directive",
      link:function(scope,element,attribute){
        var handler = $rootScope.$on("secondDirective", 
            function (event, args) {
              console.log("First Directive Data: " + args);
        });

        $rootScope.$broadcast("OnChildDirectiveCreated", {
            "message": "I'm second directive",
            "id":      "secondDirective"
        });
      }
    }
 })

and the first directive: 和第一个指令:

angular.module("app").directive("first", function($rootScope){
    return {
      template: "First Directive",
      link:function(scope,element,attribute){
           $rootScope.$on("OnChildDirectiveCreated", function(event, args) {
              $rootScope.$broadcast(args.id, someData);
           });
      }
   }
})

Since you are using a parent child structure, it is always guaranteed that the first directive will be ready when child directives are ready. 由于您使用的是父子结构,因此始终可以确保当子指令就绪时,第一个指令也将就绪。 Using this solution you could use many child directives. 使用此解决方案,您可以使用许多子指令。 Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM