最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angularjs event communication between directives with publishsubscribe - Stack Overflow

programmeradmin2浏览0评论

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

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

Share Improve this question asked May 5, 2016 at 8:40 bartelomabarteloma 6,88516 gold badges94 silver badges209 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

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 pleted 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 munication 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!

发布评论

评论列表(0)

  1. 暂无评论