AngularJS中控制器之间的正确通信方式是什么?

控制器之间通信的正确方式是什么?

我目前正在使用涉及window的可怕软糖:

function StockSubgroupCtrl($scope, $http) {
    $scope.subgroups = [];
    $scope.handleSubgroupsLoaded = function(data, status) {
        $scope.subgroups = data;
    }
    $scope.fetch = function(prod_grp) {
        $http.get('/api/stock/groups/' + prod_grp + '/subgroups/').success($scope.handleSubgroupsLoaded);
    }
    window.fetchStockSubgroups = $scope.fetch;
}

function StockGroupCtrl($scope, $http) {
    ...
    $scope.select = function(prod_grp) {
        $scope.selectedGroup = prod_grp;
        window.fetchStockSubgroups(prod_grp);
    }
}

编辑 :在这个答案中解决的问题已在angular.js版本1.2.7中解决。 $broadcast现在避免了在未注册的范围上冒泡,运行速度与$发射一样快。 $广播表演与角度为1.2.16的$ emit相同

所以,现在你可以:

  • 使用$rootScope $broadcast
  • 使用需要了解事件的本地$scope中的$on监听

  • 下面的原始答案

    我强烈建议不要使用$rootScope.$broadcast + $scope.$on ,而是使用$rootScope.$emit + $rootScope.$on 。 前者可能会导致@numan引发的严重性能问题。 这是因为这个事件会在所有范围内都会发生。

    然而,后者(使用$rootScope.$emit + $rootScope.$on不会从该遭受并且因此可以被用作快速通信信道!

    $emit的角度文档:

    通过范围层次向上调度事件名称,通知注册

    由于在$rootScope之上没有作用域,因此不会冒泡。 使用$rootScope.$emit() / $rootScope.$on()作为EventBus是完全安全的。

    但是,从控制器内部使用它时有一个问题。 如果直接绑定到控制器内的$rootScope.$on() ,则必须在本地$scope被销毁时自行清理绑定。 这是因为控制器(与服务相反)可以在应用程序的整个生命周期中多次实例化,这会导致绑定总结,最终在各处产生内存泄漏:)

    要取消注册,只需监听$scope$destroy事件,然后调用$rootScope.$on返回的函数。

    angular
        .module('MyApp')
        .controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {
    
                var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
                    console.log('foo');
                });
    
                $scope.$on('$destroy', unbind);
            }
        ]);
    

    我会说,这不是一个真正的角度特定的事情,因为它也适用于其他的EventBus实现,所以你必须清理资源。

    但是,您可以让这些情况更轻松。 例如,您可以修补$rootScope并为其指定一个$onRootScope ,该$onRootScope订阅$rootScope上发出的事件,但也会在本地$scope被销毁时直接清除处理程序。

    猴子修补$rootScope以提供这种$onRootScope方法的最$onRootScope方法是通过一个装饰器(一个运行块可能会做得很好,但是pssst,不要告诉任何人)

    为了确保枚举$scope $onRootScope属性不会出现意外,我们使用Object.defineProperty()并将enumerable设置为false 。 请记住,您可能需要一个ES5垫片。

    angular
        .module('MyApp')
        .config(['$provide', function($provide){
            $provide.decorator('$rootScope', ['$delegate', function($delegate){
    
                Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
                    value: function(name, listener){
                        var unsubscribe = $delegate.$on(name, listener);
                        this.$on('$destroy', unsubscribe);
    
                        return unsubscribe;
                    },
                    enumerable: false
                });
    
    
                return $delegate;
            }]);
        }]);
    

    使用这种方法,上面的控制器代码可以简化为:

    angular
        .module('MyApp')
        .controller('MyController', ['$scope', function MyController($scope) {
    
                $scope.$onRootScope('someComponent.someCrazyEvent', function(){
                    console.log('foo');
                });
            }
        ]);
    

    因此,作为所有这些的最终结果,我强烈建议您使用$rootScope.$emit + $scope.$onRootScope

    顺便说一句,我试图说服角度团队解决角内核问题。 这里有一个讨论:https://github.com/angular/angular.js/issues/4574

    下面是一个jsperf,它显示了$broadcast $scope的正常情况下$broadcast带来的影响。

    http://jsperf.com/rootscope-emit-vs-rootscope-broadcast

    jsperf结果


    这里最好的答案是从@ozmalifeguard已经提到的角度问题中解决(至少在版本> 1.2.16和“可能更早的版本”)。 但是我没有一个真正的解决方案,而只是阅读所有这些答案

    在我看来,现在的答案应该是

  • 使用$rootScope $broadcast
  • 使用需要了解事件的本地$scope中的$on监听
  • 因此发布

    // EXAMPLE PUBLISHER
    angular.module('test').controller('CtrlPublish', ['$rootScope', '$scope',
    function ($rootScope, $scope) {
    
      $rootScope.$broadcast('topic', 'message');
    
    }]);
    

    并订阅

    // EXAMPLE SUBSCRIBER
    angular.module('test').controller('ctrlSubscribe', ['$scope',
    function ($scope) {
    
      $scope.$on('topic', function (event, arg) { 
        $scope.receiver = 'got your ' + arg;
      });
    
    }]);
    

    Plunkers

  • Regular $ scope语法(如上所示)
  • 新的Controller As语法
  • 如果将监听器注册到本地$scope ,则在关联的控制器被删除时,它将被$destroy本身自动$destroy


    对于PubSub通信,使用$ rootScope。$ broadcast和$ scope。$ on。

    另外,请看这篇文章:AngularJS - 在控制器之间进行通信

    链接地址: http://www.djcxy.com/p/77599.html

    上一篇: What's the correct way to communicate between controllers in AngularJS?

    下一篇: Stuck trying to bootstrap Windows server using Chef