angularjs angularjs-scope

ng-href angularjs



AngularJS: evento de difusión de la directiva (3)

He visto gente haciendo esto desde cualquier parte de su código:

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

y luego en algún controlador:

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

Ahora, me gustaría difundir un evento de una directiva. ¿Es una buena práctica transmitirlo a nivel de rootScope? Me gustaría manejar este evento en un controlador. ¿Puedo usar $ scope, o aún tengo que escuchar en $ rootScope?


En mi caso, solo quiero transmitir un mensaje incluso desde una directiva al controlador de la vista, en el que utilizo la directiva. ¿Sigue teniendo sentido usar broadcast entonces?

Haría que la directiva invoque un método en el controlador, que se especifica en el HTML donde se usa la directiva:

Para una directiva que usa un alcance aislado:

<div my-dir ctrl-fn="someCtrlFn(arg1)"></div> app.directive(''myDir'', function() { return { scope: { ctrlFn: ''&'' }, link: function(scope, element, attrs) { ... scope.ctrlFn({arg1: someValue}); }

Para una directiva que no usa un alcance aislado:

<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} ); }


Aquí hay un ejemplo de TypeScript sobre cómo recuperar un método en el controlador desde una directiva incrustada. Lo más importante a tener en cuenta es que el nombre del parámetro de la directiva para su devolución de llamada utiliza un & cuando está definido, y cuando llama a esa devolución de llamada no debe usar parámetros posicionales sino un objeto con propiedades que tengan los nombres de los parámetros en el destino.

Registre la directiva cuando crea su módulo de aplicación:

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

El código de registro es el siguiente:

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()); } }

El controlador de la directiva se vería así

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 }); } } }

El HTML de la directiva se parecería a esto

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

La vista principal tendrá una instancia de su directiva como tal

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

Ahora todo lo que necesita en su MainController es un método

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