Javascript 使用 $scope.$emit 和 $scope.$on

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14502006/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 17:01:56  来源:igfitidea点击:

Working with $scope.$emit and $scope.$on

javascriptangularjs

提问by Paul Kononenko

How can I send my $scopeobject from one controller to another using .$emitand .$onmethods?

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

function firstCtrl($scope) {
    $scope.$emit('someEvent', [1,2,3]);
}

function secondCtrl($scope) {
    $scope.$on('someEvent', function(mass) { console.log(mass); });
}

It doesn't work the way I think it should. How do $emitand $onwork?

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

回答by zbynour

First of all, parent-child scope relation does matter. You have two possibilities to emit some event:

首先,父子作用​​域关系很重要。您有两种可能性来发出一些事件:

  • $broadcast-- dispatches the event downwards to all child scopes,
  • $emit-- dispatches the event upwards through the scope hierarchy.
  • $broadcast-- 向下调度事件到所有子作用域,
  • $emit-- 通过作用域层次向上调度事件。

I don't know anything about your controllers (scopes) relation, but there are several options:

我对您的控制器(范围)关系一无所知,但有几种选择:

  1. If scope of firstCtrlis parent of the secondCtrlscope, your code should work by replacing $emitby $broadcastin firstCtrl:

    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 you can inject $rootScopeinto the controller and broadcast the event to 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 controller to scopes upwards you can use $scope.$emit. If scope of firstCtrlis parent of the secondCtrlscope:

    function firstCtrl($scope)
    {
        $scope.$on('someEvent', function(event, data) { console.log(data); });
    }
    
    function secondCtrl($scope)
    {
        $scope.$emit('someEvent', [1,2,3]);
    }
    
  1. 如果 scope offirstCtrl是作用域的父级,则secondCtrl您的代码应该通过替换$emit$broadcastin来工作firstCtrl

    function firstCtrl($scope)
    {
        $scope.$broadcast('someEvent', [1,2,3]);
    }
    
    function secondCtrl($scope)
    {
        $scope.$on('someEvent', function(event, mass) { console.log(mass); });
    }
    
  2. 如果您的范围之间没有父子关系,您可以注入$rootScope控制器并将事件广播到所有子范围(即也secondCtrl)。

    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,3]);
    }
    
  3. 最后,当您需要将事件从子控制器分派到范围向上时,您可以使用$scope.$emit. 如果范围firstCtrl是范围的父级secondCtrl

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

回答by Thalis K.

I would additionally suggest a 4th option as a better alternative to the proposed options by @zbynour.

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

Use $rootScope.$emitrather than $rootScope.$broadcastregardless of the relationship between trasmitting and receiving controller. That way, the event remains within the set of $rootScope.$$listenerswhereas with $rootScope.$broadcastthe event propagates to all children scopes, most of which will probably not be listeners of that event anyway. And of course in the receiving controller's end you just use $rootScope.$on.

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

For this option you must remember to destroy the controller's rootScope listeners:

对于此选项,您必须记住销毁控制器的 rootScope 侦听器:

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

回答by SoEzPz

How can I send my $scope object from one controller to another using .$emit and .$on methods?

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

You can send any object you want within the hierarchy of your app, including $scope.

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

Here is a quick idea about how broadcastand emitwork.

以下是有关广播发射如何工作的快速了解。

Notice the nodes below; all nested within node 3. You use broadcastand emitwhen you have this scenario.

注意下面的节点;全部嵌套在节点 3中。当您遇到这种情况时,您可以使用广播发射

Note:The number of each node in this example is arbitrary; it could easily be the number one; the number two; or even the number 1,348. Each number is just an identifier for this example. The point of this example is to show nesting of Angular controllers/directives.

注意:本例中每个节点的数量是任意的;它很容易成为第一;第二个;甚至是 1,348。每个数字只是此示例的标识符。这个例子的重点是展示 Angular 控制器/指令的嵌套。

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

Check out this tree. How do you answer the following questions?

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

Note:There are other ways to answer these questions, but here we'll discuss broadcastand emit. Also, when reading below text assume each number has it's own file (directive, controller) e.x. one.js, two.js, three.js.

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

How does node 1speak to node 3?

如何节点1所讲至节点3

In file one.js

在文件one.js 中

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

In file three.js- the uppermost node to all children nodes needed to communicate.

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

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

How does node 2 speak to node 3?

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

In file two.js

在文件two.js 中

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

In file three.js- the uppermost node to all children nodes needed to communicate.

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

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

How does node 3 speak to node 1 and/or node 2?

节点 3 如何与节点 1 和/或节点 2 通信?

In file three.js- the uppermost node to all children nodes needed to communicate.

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

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

In file one.js&& two.jswhichever file you want to catch the message or both.

在文件one.js&& two.js 中,您想要捕获消息的任何文件或两者。

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

How does node 2 speak to node 1?

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

In file two.js

在文件two.js 中

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

In file three.js- the uppermost node to all children nodes needed to communicate.

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

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

In file one.js

在文件one.js 中

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

HOWEVER

然而

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.

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

Here is what I like to do.

这是我喜欢做的事情。

In the uppermost PARENT NODE ( 3in this case... ), which may be your parent controller...

在最上面的父节点(在这种情况下为3...),它可能是您的父控制器...

So, in file three.js

所以,在文件three.js

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

Now in any of the child nodes you only need to $emitthe message or catch it using $on.

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

NOTE:It is normally quite easy to cross talk in one nested path without using $emit, $broadcast, or $on, which means most use cases are for when you are trying to get node 1to communicate with node 2or vice versa.

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

How does node 2 speak to node 1?

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

In file two.js

在文件two.js 中

scope.$emit('pushChangesToAllNodes', sendNewChanges());

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

In file three.js- the uppermost node to all children nodes needed to communicate.

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

We already handled this one remember?

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

In file one.js

在文件one.js 中

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

You will still need to use $onwith each specific value you want to catch, but now you can create whatever you like in any of the nodes without having to worry about how to get the message across the parent node gap as we catch and broadcast the generic pushChangesToAllNodes.

您仍然需要将$on与您想要捕获的每个特定值一起使用,但是现在您可以在任何节点中创建您喜欢的任何内容,而不必担心在我们捕获和广播时如何通过父节点间隙获取消息通用pushChangesToAllNodes

Hope this helps...

希望这可以帮助...

回答by Ved

To send $scope objectfrom one controller to another, I will discuss about $rootScope.$broadcastand $rootScope.$emithere as they are used most.

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

Case 1:

案例一

$rootScope.$broadcast:-

$rootScope.$broadcast:-

$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name

$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event

$rootScopelistener are not destroyed automatically. You need to destroy it using $destroy. It is better to use $scope.$onas listeners on $scopeare destroyed automatically i.e. as soon as $scope is destroyed.

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

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

Or,

或者,

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

  }
  $scope.$on('$destroy', function() {
        customeEventListener();
  });

Case 2:

案例2:

$rootScope.$emit:

$rootScope.$emit:

   $rootScope.$emit('myEvent',$scope.data);

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

The major difference in $emit and $broadcast is that $rootScope.$emit event must be listened using $rootScope.$on, because the emitted event never comes down through the scope tree..
In this case also you must destroy the listener as in the case of $broadcast.

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

Edit:

编辑:

I prefer not to use $rootScope.$broadcast + $scope.$onbut use $rootScope.$emit+ $rootScope.$on. The $rootScope.$broadcast + $scope.$oncombo can cause serious performance problems. That is because the event will bubble down through all scopes.

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

Edit 2:

编辑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.

此答案中解决的问题已在 angular.js 版本 1.2.7 中解决。$broadcast 现在避免在未注册的范围内冒泡,并且运行速度与 $emit 一样快。

回答by kyasar

You must use $rootScope to send and capture events between controllers in same app. Inject $rootScope dependency to your controllers. Here is a working example.

您必须使用 $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); });
        }
}

Events linked into $scope object just work in the owner controller. Communication between controllers is done via $rootScope or Services.

链接到 $scope 对象的事件只在所有者控制器中工作。控制器之间的通信是通过 $rootScope 或服务完成的。

回答by ribhu

You can call a service from your controller that returns a promise and then use it in your controller. And further use $emitor $broadcastto inform other controllers about it. In my case, I had to make http calls through my service, so I did something like this :

你可以从你的控制器调用一个返回一个 promise 的服务,然后在你的控制器中使用它。并进一步使用$emit$broadcast通知其他控制器。就我而言,我必须通过我的服务进行 http 调用,所以我做了这样的事情:

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

and my service looks like this

我的服务看起来像这样

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

        }

    }])

回答by trai bui

This is my function:

这是我的功能:

$rootScope.$emit('setTitle', newVal.full_name);

$rootScope.$on('setTitle', function(event, title) {
    if (scope.item) 
        scope.item.name = title;
    else 
        scope.item = {name: title};
});

回答by Prashant_M

<!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>

回答by Shushanth Pallegar

Below code shows the two sub-controllers from where the events are dispatched upwards to parent controller (rootScope)

下面的代码显示了两个子控制器,从那里将事件向上分派到父控制器(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 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/

http://jsfiddle.net/shushanthp/zp6v0rut/

回答by Vasyl Gutnyk

Scope(s) can be used to propagate, dispatch event to the scope children or parent.

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

$emit- propagates the event to parent. $broadcast- propagates the event to children. $on- method to listen the events, propagated by $emit and $broadcast.

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

example index.html:

示例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>

example app.js:

示例app.js

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

Here u can test code: http://jsfiddle.net/zp6v0rut/41/

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