首页 文章

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

提问于
浏览
851

如何使用 .$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 如何工作?

13 回答

  • 10

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

    @params

    • 事件是包含事件信息的事件对象

    • 被调用者传递的 args(注意,这只能是一个总是更好地发送到字典对象中)

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

    此外,如果您尝试在不同的控制器上获得共享的信息,还有另一种方法可以实现这一点,即角度服务 . 由于服务是单例,因此可以跨控制器存储和获取信息 . 简单地创建getter和该服务中的setter函数,公开这些函数,在服务中创建全局变量并使用它们来存储信息

  • 108

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

    您可以在应用层次结构中发送所需的任何对象,包括 $scope .

    以下是关于 broadcastemit 如何工作的快速概念 .

    注意下面的节点;全部嵌套在节点3中 . 如果有此方案,则使用 broadcastemit .

    Note: 此示例中每个节点的数量是任意的;它很容易成为头号人物;二号;甚至是1,348号 . 每个数字只是此示例的标识符 . 这个例子的重点是显示Angular控制器/指令的嵌套 .

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

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

    Note: 还有其他方法可以回答这些问题,但在这里我们将讨论 broadcastemit . 此外,当阅读下面的文本时,假设每个数字都有自己的文件(指令,控制器)e.x. 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 && two.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));
    

    HOWEVER

    如果所有这些嵌套的子节点都试图像这样进行通信,您将很快看到许多$ on,$ broadcast和$ emit .

    这是我喜欢做的事情 .

    在最上面的PARENT NODE(在这种情况下是 3 ......),这可能是你的父控制器......

    所以,在文件 three.js

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

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

    NOTE: 在不使用 $emit$broadcast$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 与您想要捕获的每个特定值一起使用,但现在您可以在任何节点中创建任何您喜欢的内容,而不必担心如何在父节点间隙中获取消息,因为我们捕获并广播通用 pushChangesToAllNodes .

    希望这可以帮助...

  • 38

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

    Case 1

    $ rootScope $广播: -

    $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被销毁 .

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

    要么,

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

    Case 2:

    . $ rootScope $发出:

    $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. .
    在这种情况下,你也必须像$ broadcast那样销毁监听器 .

    Edit:

    我不想使用$ rootScope . $ broadcast $ scope . $ on但是使用$ rootScope . $ emit $ rootScope . $ on . 组合上的$ rootScope . $ broadcast $ scope . $会导致严重的性能问题 . 那是因为事件将在所有范围内向下消失 .

    Edit 2

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

  • 1
    <!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>
    
  • 3

    这是我的功能:

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

    您必须使用$ 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完成 .

  • 1476

    我最终添加了一个外部EventEmitter库来作为服务进行投影,并将其注入到我需要的任何地方 . 因此,我可以在任何地方“发射”和“开启”任何地方,而无需关心范围继承 . 这种方式不那么麻烦,肯定会有更好的性能 . 对我来说也更具可读性 .

    通配符支持:EventEmitter2

    表现良好:eventemitter3

    其他选择:Drip

  • 0

    范围可用于传播,将事件分派给范围子项或父项 .

    $emit - 将事件传播到父级 . $broadcast - 将事件传播给子项 . $on - 侦听事件的方法,由$ emit和$ broadcast传播 .

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

  • 0

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

    • $broadcast - 将事件向下调度到所有子范围,

    • $emit - 通过范围层次结构向上调度事件 .

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

    • 如果 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); });
    }
    
    • 如果您的范围之间没有父子关系,您可以将 $rootScope 注入控制器并将事件广播到所有子范围(即 secondCtrl ) .
    function firstCtrl($rootScope)
    {
        $rootScope.$broadcast('someEvent', [1,2,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]);
    }
    
  • 3

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

    无论传输和接收控制器之间的关系如何,都使用 $rootScope.$emit 而不是 $rootScope.$broadcast . 这样,事件仍然在 $rootScope.$$listeners 的集合内,而对于 $rootScope.$broadcast ,事件传播到所有子范围,其中大多数可能不是该事件的监听者 . 当然,在接收控制器的最后,你只需使用 $rootScope.$on .

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

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

    最简单的方法:

    HTML

    <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>
    
  • 2

    您可以从控制器调用返回承诺的服务,然后在控制器中使用它 . 并进一步使用 $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
            })
        }
    

    我的服务看起来像这样

    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);
                    });
    
            }
    
        }])
    
  • 141

    下面的代码显示了从事件向上调度到父控制器的两个子控制器(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/

相关问题