AngularJS:来自指令的广播事件

时间:2013-04-24 18:09:06

标签: angularjs angularjs-scope

我见过人们在他们的代码中的任何地方都这样做:

$rootScope.$broadcast('someEvent', someParameter); 

然后在某个控制器中:

$rootScope.$on('someEvent', function(event, e){ /* implementation here */ });

现在,我想从一个指令中宣传一个事件。在rootScope级别播放它是一种好习惯吗?我想在控制器中处理这个事件。我可以使用$ scope,还是我还要听$ rootScope?

3 个答案:

答案 0 :(得分:78)

  

就我而言,我只想将一个指令中的事件广播到视图的控制器,我在其中使用该指令。那么使用广播还有意义吗?

我会让指令在控制器上调用一个方法,该方法在使用该指令的HTML中指定:

对于使用隔离范围的指令:

<div my-dir ctrl-fn="someCtrlFn(arg1)"></div>

app.directive('myDir', function() {
  return {
    scope: { ctrlFn: '&' },
    link: function(scope, element, attrs) {
       ...
       scope.ctrlFn({arg1: someValue});
    }

对于不使用隔离范围的指令:

<div my-dir ctrl-fn="someCtrlFn(arg1)"></div>

app.directive('myDir', function($parse) {
  return {
    scope: true,  // or no new scope -- i.e., remove this line
    link: function(scope, element, attrs) {
       var invoker = $parse(attrs.ctrlFn);
       ...
       invoker(scope, {arg1: someValue} );
    }

答案 1 :(得分:13)

通常不使用$ rootScope作为全局,除非你真的知道自己在做什么,否则不应该污染它。我建议您阅读this article about communication between services, directives and controllers

答案 2 :(得分:0)

这是一个TypeScript示例,说明如何从嵌入式指令回调控制器上的方法。最值得注意的是,你的回调的指令参数名称使用&amp;在定义时,并且在调用该回调时,您不应该使用位置参数,而是使用具有在目标中具有参数名称的属性的对象。

在创建应用模块时注册指令:

module MyApp {
    var app: angular.IModule = angular.module("MyApp");
    MyApp.Directives.FileUploader.register(app);
}

注册码如下:

module MyApp.Directives.FileUploader {
  class FileUploaderDirective implements angular.IDirective {
      public restrict: string = "E";
      public templateUrl: string = "/app/Directives/FileUploader/FileUploaderDirective.html";

      //IMPORTANT - Use & to identify this as a method reference
      public scope: any = {
        onFileItemClicked: "&"
      };
      public controller: string = "MyApp.Directives.FileUploader.Controller";
      public controllerAs: string = "controller";
      public bindToController: boolean = true;
      public transclude: boolean = true;
      public replace: boolean = true;
  }

  export function register(app: angular.IModule) {
      app.controller("MyApp.Directives.FileUploader.Controller", Controller);
      app.directive("fileUploader", () => new FileUploaderDirective());
  }
}

指令的控制器看起来像这样

module MyApp.Directives.FileUploader {
    export class Controller {
        public files: string[] = ["One", "Two", "Three"];
        //The callback specified in the view that created this directive instance
        public onFileItemClicked: (fileItem) => void;

        // This is the controller method called from its HTML's ng-click
        public fileItemClicked(fileItem) {
            //IMPORTANT: Don't use comma separated parameters,
            //instead use an object with property names to act as named parameters
            this.onFileItemClicked({
                fileItem: fileItem
            });
        }
    }
}

指令的HTML看起来像这样

<ul>
  <li ng-repeat="item in controller.files" ng-click="controller.fileItemClicked (item)">
    {{ item }}
  </li>
</ul>

主视图将包含您的指令实例,如此

<body ng-app="MyApp" ng-controller="MainController as controller">
  <file-uploader on-file-item-clicked="controller.fileItemClicked(fileItem)"/>
</body>

现在您在MainController上需要的只是一个方法

public fileItemClicked(fileItem) {
  alert("Clicked " + fileItem);
}