来自服务的$ emit或$ broadcast事件,并在控制器(或几个)中监听它们

时间:2014-04-11 13:23:41

标签: javascript angularjs angularjs-directive angularjs-scope

我编写了一个简单的示例,我想从服务中发出/广播事件,我希望控制器能够监听该事件并更改UI,但我无法使其工作并调试代码似乎在监听器中停止但它没有执行该功能。

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

服务:

angular.module('ServiceModule', []).
service('servicetest', ['$rootScope', function($rootScope){
    this.test = function(){
      $rootScope.$emit('testevent');
    };
}]);

控制器

angular.module('ControllerModule', ['ServiceModule']).
    controller('ControllerTest', ['$scope','$rootScope','servicetest', function($scope, $rootScope, servicetest){
      $scope.name = 'World';
      servicetest.test();
      $rootScope.$on('testevent', function(){
        $scope.name = 'Joe';
      });
    }]);

索引

<!DOCTYPE html>
<html ng-app="ControllerModule">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
    <script src="controller.js"></script>
    <script src="service.js"></script>
  </head>

  <body ng-controller="ControllerTest">
    <p>Hello {{name}}!</p>
  </body>

</html>

解决方案:

正如ivarni或Walter品牌报道的那样,触发事件的服务功能的调用必须放在听众之后,如果不是,你正在触发一个听众无法听到的事件。< / p>

我们只需按如下方式更改控制器:

服务

angular.module('ControllerModule', ['ServiceModule']).
        controller('ControllerTest', ['$scope','$rootScope','servicetest', function($scope, $rootScope, servicetest){
          $scope.name = 'World';
          $rootScope.$on('testevent', function(){
            $scope.name = 'Joe';
          });
          servicetest.test();
        }]);

3 个答案:

答案 0 :(得分:4)

您在连接听众之前触发了该事件。

试试这个:

  $rootScope.$on('testevent', function(){
    $scope.name = 'Joe';
  });
  servicetest.test();

答案 1 :(得分:2)

将servicetest.test()放在您的侦听器下方,如下所示:

  $rootScope.$on('testevent', function(){
    $scope.name = 'Joe';
  });
  servicetest.test();

您在调用test()之后立即附加了侦听器,并且只是错过了该事件。

答案 2 :(得分:2)

我发现在中型应用程序中运行效果最好的解决方案是在$ emit函数周围创建一个包装器,并在几毫秒内延迟$ emit,这足以让所有事件都被注册。

您还可以在包装器中引入更多好东西,比如将它传递给当前的$ scope,或者让它创建$ rootscope的新子范围(下面只有一个级别,因此传播时它仍然会很快)最多$ rootScope),并将其用作数据通道,范围终止后的事件销毁等等......

以下是完整的源代码:http://jsfiddle.net/gabrielcatalin/2uRr7

这是一段摘录:

/**
 * Waits a given amount of time before calling emitting
 * This works well when the event registration happens before emitting.
 *
 * @param name
 * @param fn
 * @param wait
 */
this.delayEmit = function (name, fn, wait) {
    // Because of the $scope's lifecycle the $emit(publish) happens after the $on(subscription)
    //  therefore that needs to be taken care of with a delay
    $timeout(function () {
        self.emit(name, fn);
    }, wait || 100);
}