Working with $scope.$emit and $scope.$on
如何使用
1 2 3 4 5 6 7 | function firstCtrl($scope) { $scope.$emit('someEvent', [1,2,3]); } function secondCtrl($scope) { $scope.$on('someEvent', function(mass) { console.log(mass); }); } |
我认为这不可行。
首先,父子范围关系很重要。您有两种可能发出某些事件:
$broadcast --将事件向下发送到所有子作用域,$emit --通过作用域层次结构向上发送事件。
我对您的控制器(作用域)关系一无所知,但有以下几种选择:
如果
1 2 3 4 5 6 7 8 9 | function firstCtrl($scope) { $scope.$broadcast('someEvent', [1,2,3]); } function secondCtrl($scope) { $scope.$on('someEvent', function(event, mass) { console.log(mass); }); } |
如果您的作用域之间没有父子关系,则可以将
1 2 3 4 | function firstCtrl($rootScope) { $rootScope.$broadcast('someEvent', [1,2,3]); } |
最后,当您需要从子控制器调度事件时要向上搜索,可以使用
1 2 3 4 5 6 7 8 9 | function firstCtrl($scope) { $scope.$on('someEvent', function(event, data) { console.log(data); }); } function secondCtrl($scope) { $scope.$emit('someEvent', [1,2,3]); } |
我还建议使用第四个选项,作为@zbynour提议的选项的更好替代方案。
使用
对于此选项,必须记住销毁控制器的rootscope侦听器:
1 2 3 4 | var unbindEventHandler = $rootScope.$on('myEvent', myHandler); $scope.$on('$destroy', function () { unbindEventHandler(); }); |
How can I send my $scope object from one controller to another using .$emit and .$on methods?
您可以发送应用程序层次结构中所需的任何对象,包括$scope。
这里有一个关于广播和发射如何工作的快速想法。
注意下面的节点;所有都嵌套在节点3中。当您有这个场景时,可以使用广播和发射。
注意:本例中每个节点的编号是任意的;可以很容易地是数字1、数字2,甚至是数字1348。对于这个例子,每个数字只是一个标识符。本例的重点是显示角度控制器/指令的嵌套。
1 2 3 4 5 6 7 | 3 ------------ | | ----- ------ 1 | 2 | --- --- --- --- | | | | | | | | |
看看这棵树。你如何回答下列问题?
注意:还有其他方法来回答这些问题,但这里我们将讨论广播和发射。另外,在阅读下面的文本时,假设每个数字都有自己的文件(指令、控制器)e.x.one.js、2.js和3.js。
节点1如何与节点3通信?
在文件ON.JS中
1 | scope.$emit('messageOne', someValue(s)); |
在文件three.js中-与所有需要通信的子节点的最上面的节点。
1 | scope.$on('messageOne', someValue(s)); |
节点2如何与节点3通信?
在文件中
1 | scope.$emit('messageTwo', someValue(s)); |
在文件three.js中-与所有需要通信的子节点的最上面的节点。
1 | scope.$on('messageTwo', someValue(s)); |
节点3如何与节点1和/或节点2说话?
在文件three.js中-与所有需要通信的子节点的最上面的节点。
1 | scope.$broadcast('messageThree', someValue(s)); |
在文件one.js&;&;two.js中,无论您想捕获消息的哪个文件,或者两者都要捕获。
1 | scope.$on('messageThree', someValue(s)); |
节点2如何与节点1通信?
在文件中
1 | scope.$emit('messageTwo', someValue(s)); |
在文件three.js中-与所有需要通信的子节点的最上面的节点。
1 2 3 | scope.$on('messageTwo', function( event, data ){ scope.$broadcast( 'messageTwo', data ); }); |
在文件ON.JS中
1 | scope.$on('messageTwo', someValue(s)); |
然而
When you have all these nested child nodes trying to communicate like this, you will quickly see many $on's, $broadcast's, and $emit's.
这是我喜欢做的。
在最上面的父节点中(在本例中为3…),可能是您的父控制器…
所以,在文件3.js中
1 2 3 | scope.$on('pushChangesToAllNodes', function( event, message ){ scope.$broadcast( message.name, message.data ); }); |
现在,在任何子节点中,您只需要$emit该消息或使用$on捕获它。
注意:在一个嵌套的路径中,不使用$emit、$broadcast或$on就可以很容易地进行交叉对话,这意味着大多数用例都是在您试图让节点1与节点2通信时使用的,反之亦然。
节点2如何与节点1通信?
在文件中
1 2 3 4 5 | scope.$emit('pushChangesToAllNodes', sendNewChanges()); function sendNewChanges(){ // for some event. return { name: 'talkToOne', data: [1,2,3] }; } |
在文件three.js中-与所有需要通信的子节点的最上面的节点。
我们已经处理过了,记得吗?
在文件ON.JS中
1 2 3 4 5 | scope.$on('talkToOne', function( event, arrayOfNumbers ){ arrayOfNumbers.forEach(function(number){ console.log(number); }); }); |
您仍然需要将$on用于要捕获的每个特定值,但现在您可以在任何节点中创建您喜欢的任何内容,而无需担心在捕获和广播通用pushchangestoallnodes时如何跨越父节点间隙获取消息。
希望这有帮助…
为了将
案例1:
$rootscope.$broadcast:-
1 2 3 | $rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name $rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event |
1 | $scope.$on('myEvent', function(event, data) {} |
或者,
1 2 3 4 5 6 | var customeEventListener = $rootScope.$on('myEvent', function(event, data) { } $scope.$on('$destroy', function() { customeEventListener(); }); |
案例2:
$rootscope.$emit:
1 2 3 | $rootScope.$emit('myEvent',$scope.data); $rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works |
$emit和$broadcast的主要区别在于$rootscope.$emit事件必须使用$rootscope.$on进行侦听,因为所发出的事件从未通过作用域树发生。在这种情况下,您还必须像$broadcast那样销毁侦听器。
编辑:
I prefer not to use
$rootScope.$broadcast + $scope.$on but use
$rootScope.$emit+ $rootScope.$on . The$rootScope.$broadcast + combo can cause serious performance problems. That is
$scope.$on
because the event will bubble down through all scopes.
编辑2:
The issue addressed in this answer have been resolved in angular.js
version 1.2.7. $broadcast now avoids bubbling over unregistered scopes
and runs just as fast as $emit.
必须使用$rootscope在同一应用程序中的控制器之间发送和捕获事件。向控制器注入$rootscope依赖项。这是一个有效的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 | app.controller('firstCtrl', function($scope, $rootScope) { function firstCtrl($scope) { { $rootScope.$emit('someEvent', [1,2,3]); } } app.controller('secondCtrl', function($scope, $rootScope) { function secondCtrl($scope) { $rootScope.$on('someEvent', function(event, data) { console.log(data); }); } } |
链接到$scope对象的事件只在所有者控制器中工作。控制器之间的通信通过$rootscope或服务完成。
您可以从控制器调用返回承诺的服务,然后在控制器中使用该服务。并进一步使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function ParentController($scope, testService) { testService.getList() .then(function(data) { $scope.list = testService.list; }) .finally(function() { $scope.$emit('listFetched'); }) function ChildController($scope, testService) { $scope.$on('listFetched', function(event, data) { // use the data accordingly }) } |
我的服务看起来像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | app.service('testService', ['$http', function($http) { this.list = []; this.getList = function() { return $http.get(someUrl) .then(function(response) { if (typeof response.data === 'object') { list = response.data.results; return response.data; } else { // invalid response return $q.reject(response.data); } }, function(response) { // something went wrong return $q.reject(response.data); }); } }]) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"> var app = angular.module('MyApp',[]); app.controller('parentCtrl',function($scope){ $scope.$on('MyEvent',function(event,data){ $scope.myData = data; }); }); app.controller('childCtrl',function($scope){ $scope.fireEvent = function(){ $scope.$emit('MyEvent','Any Data'); } }); </head> <body ng-app="MyApp"> {{myData}} <button ng-click="fireEvent()">Fire Event</button> </body> </html> |
这是我的职责:
1 2 3 4 5 6 7 8 | $rootScope.$emit('setTitle', newVal.full_name); $rootScope.$on('setTitle', function(event, title) { if (scope.item) scope.item.name = title; else scope.item = {name: title}; }); |
最后,我添加了一个外部EventEmitter库作为一个服务来项目,并在我需要的地方注入它。所以我可以在任何地方"发出"和"打开"任何东西,而不需要考虑范围继承。这样做的麻烦更小,性能也更好。对我来说也更具可读性。
通配符支持:EventEmitter2
性能良好:EventEmitter3
其他备选方案:滴灌
作用域可用于向作用域子级或父级传播、分派事件。
$emit-将事件传播给父级。$broadcast-将活动传播给儿童。$on-侦听事件的方法,由$emit和$broadcast传播。
index.html示例:
1 2 3 4 5 6 | Root(Parent) scope count: {{count}} <button ng-click="$emit('MyEvent')">$emit('MyEvent')</button> <button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button> Childrent scope count: {{count}} |
示例App.js:
1 2 3 4 5 6 7 | angular.module('appExample', []) .controller('EventCtrl', ['$scope', function($scope) { $scope.count = 0; $scope.$on('MyEvent', function() { $scope.count++; }); }]); |
在这里,您可以测试代码:http://jsfiddle.net/zp6v0rut/41/
下面的代码显示两个子控制器,从中向上调度事件到父控制器(rootscope)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <body ng-app="App"> <p> City : {{city}} </p> <p> Address : {{address}} </p> <input type="text" ng-model="city" /> <button ng-click="getCity(city)">City !!!</button> <input type="text" ng-model="address" /> <button ng-click="getAddrress(address)">Address !!!</button> </body> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | var App = angular.module('App', []); // parent controller App.controller('parentCtrl', parentCtrl); parentCtrl.$inject = ["$scope"]; function parentCtrl($scope) { $scope.$on('cityBoom', function(events, data) { $scope.city = data; }); $scope.$on('addrBoom', function(events, data) { $scope.address = data; }); } // sub controller one App.controller('subCtrlOne', subCtrlOne); subCtrlOne.$inject = ['$scope']; function subCtrlOne($scope) { $scope.getCity = function(city) { $scope.$emit('cityBoom', city); } } // sub controller two App.controller('subCtrlTwo', subCtrlTwo); subCtrlTwo.$inject = ["$scope"]; function subCtrlTwo($scope) { $scope.getAddrress = function(addr) { $scope.$emit('addrBoom', addr); } } |
http://jsfiddle.net/shushanthp/zp6v0rut/
最简单的方法:
HTML
1 | <button ng-click="sendData();"> Send Data </button> |
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 | var app = angular.module('myApp', []); app.controller('myCtrl', function($scope, $rootScope) { function sendData($scope) { var arrayData = ['sam','rumona','cubby']; $rootScope.$emit('someEvent', arrayData); } }); app.controller('yourCtrl', function($scope, $rootScope) { $rootScope.$on('someEvent', function(event, data) { console.log(data); }); }); |
根据AngularJS事件文档,接收端应该包含具有如下结构的参数
@帕拉姆
--对象事件是包含事件信息的事件对象
--对象被调用方传递的参数(请注意,只有这样才能更好地发送到字典对象中)
另外,如果您试图在不同的控制器上获得共享的信息,还有另一种实现这一点的方法,那就是角度服务。由于服务是单件的,所以可以跨控制器存储和获取信息。只需在该服务中创建getter和setter函数,就可以公开这些函数,在服务中生成全局变量并使用它们存储信息