使用$的作用域.$emit和$的作用域.$on

如何使用.$emit.$on方法将我的$scope对象从一个控制器发送到另一个控制器?

function firstCtrl($scope) {$scope.$emit('someEvent', [1,2,3]);}
function secondCtrl($scope) {$scope.$on('someEvent', function(mass) { console.log(mass); });}

它不像我认为的那样工作。$emit$on是如何工作的?

615878 次浏览

首先,父子范围关系确实很重要。你有两种可能性发出一些事件:

  • $broadcast--将事件向下调度到所有子作用域,
  • $emit--通过作用域层次结构向上调度事件。

我对你的控制器(作用域)关系一无所知,但有几个选项:

  1. 如果firstCtrl的作用域是secondCtrl作用域的父级,则您的代码应该在firstCtrl中将$emit替换为$broadcast

    function firstCtrl($scope){$scope.$broadcast('someEvent', [1,2,3]);}
    function secondCtrl($scope){$scope.$on('someEvent', function(event, mass) { console.log(mass); });}
  2. In case there is no parent-child relation between your scopes youcan inject $rootScope into the controller and broadcast the eventto all child scopes (i.e. also secondCtrl).

    function firstCtrl($rootScope){$rootScope.$broadcast('someEvent', [1,2,3]);}
  3. Finally, when you need to dispatch the event from child controllerto scopes upwards you can use $scope.$emit. If scope of firstCtrl is parent of the secondCtrl scope:

    function firstCtrl($scope){$scope.$on('someEvent', function(event, data) { console.log(data); });}
    function secondCtrl($scope){$scope.$emit('someEvent', [1,2,3]);}

您可以从控制器调用返回Promise的服务,然后在控制器中使用它。并进一步使用$emit$broadcast通知其他控制器。在我的情况下,我必须通过我的服务进行超文本传输协议调用,所以我做了这样的事情:

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

我的服务是这样的

    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 responsereturn $q.reject(response.data);}
}, function(response) {// something went wrongreturn $q.reject(response.data);});
}
}])

我还建议第四个选项,作为@zbynour提议的选项的更好替代方案。

无论发送控制器和接收控制器之间的关系如何,都使用$rootScope.$emit而不是$rootScope.$broadcast。这样,事件保持在$rootScope.$$listeners的集合内,而使用$rootScope.$broadcast时,事件传播到所有子作用域,其中大多数可能无论如何都不是该事件的侦听器。当然,在接收控制器端,你只需使用$rootScope.$on

对于这个选项,你必须记住销毁控制器的rootScope侦听器:

var unbindEventHandler = $rootScope.$on('myEvent', myHandler);$scope.$on('$destroy', function () {unbindEventHandler();});

这是我的功能:

$rootScope.$emit('setTitle', newVal.full_name);
$rootScope.$on('setTitle', function(event, title) {if (scope.item)scope.item.name = title;elsescope.item = {name: title};});
<!DOCTYPE html><html>
<head><script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script><script>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');}});</script></head><body ng-app="MyApp"><div ng-controller="parentCtrl" ng-model="myName">
\{\{myData}}
<div ng-controller="childCtrl"><button ng-click="fireEvent()">Fire Event</button></div>
</div></body></html>

下面的代码显示了事件向上分派到父控制器(rootScope)的两个子控制器

<body ng-app="App">
<div ng-controller="parentCtrl">
<p>City : \{\{city}} </p><p> Address : \{\{address}} </p>
<div ng-controller="subCtrlOne"><input type="text" ng-model="city" /><button ng-click="getCity(city)">City !!!</button></div>
<div ng-controller="subCtrlTwo">
<input type="text" ng-model="address" /><button ng-click="getAddrress(address)">Address !!!</button>
</div>
</div>
</body>

var App = angular.module('App', []);
// parent controllerApp.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/

如何使用.$emit和.$on方法将我的$Scope对象从一个控制器发送到另一个控制器?

您可以在应用程序的层次结构中发送任何您想要的对象,包括$作用域

这里有一个关于广播发射如何工作的快速想法。

请注意下面的节点;都嵌套在节点3中。当您有这个场景时,您使用广播发射

备注:此示例中每个节点的编号是任意的;它很容易是数字1;数字2;甚至是数字1,348。每个数字只是此示例的标识符。此示例的重点是显示Angular控制器/指令的嵌套。

                 3------------|          |-----     ------1   |     2    |---   ---   ---  ---| |   | |   | |  | |

看看这棵树。你如何回答以下问题?

备注:还有其他方法来回答这些问题,但在这里我们将讨论广播发射。此外,在阅读下面的文本时,假设每个数字都有自己的文件(指令、控制器),例如one.js、two.js、three.js.

节点1如何与节点3对话?

在文件one.js

scope.$emit('messageOne', someValue(s));

在文件three.js中-通信所需的所有子节点的最上层节点。

scope.$on('messageOne', someValue(s));

节点2如何与节点3对话?

在文件two.js

scope.$emit('messageTwo', someValue(s));

在文件three.js中-通信所需的所有子节点的最上层节点。

scope.$on('messageTwo', someValue(s));

节点3如何与节点1和/或节点2对话?

在文件three.js中-通信所需的所有子节点的最上层节点。

scope.$broadcast('messageThree', someValue(s));

在文件one.js&中,无论您想捕获消息还是两者。

scope.$on('messageThree', someValue(s));

节点2如何与节点1对话?

在文件two.js

scope.$emit('messageTwo', someValue(s));

在文件three.js中-通信所需的所有子节点的最上层节点。

scope.$on('messageTwo', function( event, data ){scope.$broadcast( 'messageTwo', data );});

在文件one.js

scope.$on('messageTwo', someValue(s));

然而

当您让所有这些嵌套的子节点尝试像这样进行通信时,您将很快看到许多$on的$广播的$emit的

这是我喜欢做的。

在最上面的PARENT NODE(在本例中为3…)中,它可能是您的父控制器…

所以,在文件three.js

scope.$on('pushChangesToAllNodes', function( event, message ){scope.$broadcast( message.name, message.data );});

现在在任何子节点中,您只需要$emit消息或使用$on捕获它。

注:通常很容易在一个嵌套路径中进行串扰,而不使用$emit$广播$on,这意味着大多数用例都适用于您尝试让节点1与节点2通信,反之亦然。

节点2如何与节点1对话?

在文件two.js

scope.$emit('pushChangesToAllNodes', sendNewChanges());
function sendNewChanges(){ // for some event.return { name: 'talkToOne', data: [1,2,3] };}

在文件three.js中-通信所需的所有子节点的最上层节点。

我们已经处理过了记得吗?

在文件one.js

scope.$on('talkToOne', function( event, arrayOfNumbers ){arrayOfNumbers.forEach(function(number){console.log(number);});});

您仍然需要对每个要捕获的特定值使用$on,但现在您可以在任何节点中创建您喜欢的任何内容,而不必担心如何在捕获和广播泛型将更改推送到所有节点时跨父节点间隙获取消息。

希望这有助于…

您必须使用$rootScope在同一应用程序中的控制器之间发送和捕获事件。将$rootScope依赖项注入您的控制器。这是一个工作示例。

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或Services完成。

为了将$scope object从一个控制器发送到另一个控制器,我将在这里讨论$rootScope.$broadcast$rootScope.$emit,因为它们最常用。

案例1

广播:-

$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name
$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event

$rootScope侦听器不会自动销毁。您需要使用$destroy销毁它。最好使用$scope.$on,因为$scope上的侦听器会自动销毁,即一旦$范围被销毁。

$scope.$on('myEvent', function(event, data) {}

或者,

  var customeEventListener = $rootScope.$on('myEvent', function(event, data) {
}$scope.$on('$destroy', function() {customeEventListener();});

案例2:

$rootScope.$emit:取值范围:

   $rootScope.$emit('myEvent',$scope.data);
$rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works

$emit和$广播的主要区别在于$rootScope.$emit事件必须使用$rootScope.$on侦听,因为发出的事件永远不会通过作用域树下来。
在这种情况下,您还必须像$广播的情况一样销毁侦听器。

编辑:

我宁愿不使用$rootScope.$broadcast + $scope.$on,但使用$rootScope.$emit+ $rootScope.$on.$rootScope。$广播+组合可能会导致严重的性能问题因为事件将在所有范围内冒泡。

编辑2

这个问题已经在angular.js解决了版本1.2.7.$广播现在避免在未注册的范围内冒泡运行速度和$emit一样快。

作用域可用于将事件传播、分派给作用域子级或父级。

$emit-将事件传播给父级。$广播-将事件传播给子级。$on-侦听事件的方法,由$emit和$广播传播。

示例index.html

<div ng-app="appExample" ng-controller="EventCtrl">Root(Parent) scope count: \{\{count}}<div><button ng-click="$emit('MyEvent')">$emit('MyEvent')</button><button ng-click="$broadcast('MyEvent')">$broadcast('MyEvent')</button><br>
Childrent scope count: \{\{count}}</div></div>

示例app.js

angular.module('appExample', []).controller('EventCtrl', ['$scope', function($scope) {$scope.count = 0;$scope.$on('MyEvent', function() {$scope.count++;});}]);

在这里你可以测试代码:http://jsfiddle.net/zp6v0rut/41/

根据angularjs事件文档,接收端应该包含具有以下结构的参数

@刘宇龙

--{Object}事件是包含事件信息的事件对象

--{Object}由被调用者传递的参数(请注意,这只能是一个最好总是在字典对象中发送的参数)

$scope.$on('fooEvent', function (event, args) { console.log(args) });从你的代码

此外,如果你试图让一条共享信息在不同的控制器上可用,还有另一种方法可以实现这一点,那就是角服务。由于服务是单例,信息可以跨控制器存储和获取。只需在该服务中创建getter和setter函数,公开这些函数,在服务中制作全局变量并使用它们来存储信息

最简单的方法:

超文本标记语言

  <div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="sendData();"> Send Data </button>
</div>

javascript

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