AngularJS: трансляция события из директивы
Я видел, что люди делают это из любого места в коде:
$rootScope.$broadcast('someEvent', someParameter);
а потом в каком-то контроллере:
$rootScope.$on('someEvent', function(event, e){ /* implementation here */ });
теперь, я хотел бы broacast событие из директивы. Это хорошая практика, чтобы транслировать его на уровне метрики ? Я хотел бы обработать это событие в контроллере. Могу ли я использовать $scope, или мне все еще нужно слушать на $rootScope ?
3 ответов:
в моем случае я просто хочу транслировать даже из директивы в контроллер представления, в котором я использую директиву. Имеет ли смысл использовать широковещание тогда?
Я хотел бы, чтобы директива вызывала метод на контроллере, который указан в 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} ); }
это обычно хорошая идея, чтобы не использовать $rootScope, как это глобальный, и вы не должны загрязнять его, если вы действительно не знаете, что вы делаете. Я бы рекомендовал вам прочитать эта статья о связи между службами, директивами и контроллерами.
вот пример TypeScript о том, как вызвать метод на контроллере из встроенной директивы. Самое главное отметить, что имя параметра директивы для вашего обратного вызова использует & при определении, и при вызове этого обратного вызова вы не должны использовать позиционные параметры, а вместо этого использовать объект со свойствами, имеющими имена параметров в целевом объекте.
зарегистрировать директиву при создании модуля приложения:
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); }
Comments