简体   繁体   中英

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:

<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.

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.

In the second example:

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

Here you firstly subscribe to an event, and after that first directive sends a message. Because of this, second directive accepts an event.

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:

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. 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.

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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