控制器之间通信的正确方法是什么?
我目前正在使用一种可怕的软糖包括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);
}
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*oph 454
编辑:此答案中解决的问题已在angular.js 版本1.2.7中得到解决.$broadcast现在避免冒泡未注册的范围,并且运行速度与$ emit一样快.

所以,现在你可以:
$broadcast从$rootScope$on 从$scope需要了解事件的本地人那里听取意见原文如下
我强烈建议不要使用$rootScope.$broadcast+ $scope.$on而是使用$rootScope.$emit+ $rootScope.$on.前者会导致严重的性能问题,如@numan提出的那样.那是因为事件将在所有范围内向下消失.
然而,后者(使用$rootScope.$emit+ $rootScope.$on)不不从这个遭受并且因此可以被用作快速通信信道!
从角度文档$emit:
通过范围层次结构向上调度事件名称,通知已注册的事件
由于上面没有范围$rootScope,所以没有发生冒泡.使用$rootScope.$emit()/ $rootScope.$on()作为EventBus 是完全安全的.
但是,在Controllers中使用它时有一个问题.如果直接$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);
}
]);
Run Code Online (Sandbox Code Playgroud)
我会说,这不是一个特定角度的东西,因为它也适用于其他EventBus实现,你必须清理资源.
但是,您可以使这些案例的生活更轻松.例如,你可以修补补丁$rootScope并给它一个$onRootScope订阅发出的事件,$rootScope但也可以在本地$scope被破坏时直接清理处理程序.
猴子补丁$rootScope提供这种$onRootScope方法最干净的方法是通过一个装饰器(一个运行块可能会做得很好但是pssst,不要告诉任何人)
为了确保$onRootScope在枚举时$scope我们使用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;
}]);
}]);
Run Code Online (Sandbox Code Playgroud)
有了这种方法,上面的控制器代码可以简化为:
angular
.module('MyApp')
.controller('MyController', ['$scope', function MyController($scope) {
$scope.$onRootScope('someComponent.someCrazyEvent', function(){
console.log('foo');
});
}
]);
Run Code Online (Sandbox Code Playgroud)
所以作为所有这些的最终结果,我强烈建议你使用$rootScope.$emit+ $scope.$onRootScope.
顺便说一下,我试图说服角度团队解决角度核心内的问题.这里有一个讨论:https://github.com/angular/angular.js/issues/4574
这是一个jsperf,它显示了$broadcast在一个体面的场景中,只有100 $scope秒的性能影响会给桌面带来多少影响.
http://jsperf.com/rootscope-emit-vs-rootscope-broadcast

pos*_*est 106
这里的最佳答案是解决了一个不再存在的Angular问题(至少在版本> 1.2.16和"可能更早"),正如@zumalifeguard所提到的那样.但是,如果没有实际的解决方案,我会离开阅读所有这些答案.
在我看来,答案现在应该是
$broadcast从$rootScope$on 从$scope需要了解事件的本地人那里听取意见所以要发布
// EXAMPLE PUBLISHER
angular.module('test').controller('CtrlPublish', ['$rootScope', '$scope',
function ($rootScope, $scope) {
$rootScope.$broadcast('topic', 'message');
}]);
Run Code Online (Sandbox Code Playgroud)
并订阅
// EXAMPLE SUBSCRIBER
angular.module('test').controller('ctrlSubscribe', ['$scope',
function ($scope) {
$scope.$on('topic', function (event, arg) {
$scope.receiver = 'got your ' + arg;
});
}]);
Run Code Online (Sandbox Code Playgroud)
Plunkers
Controller As语法如果您在本地注册的监听器$scope,它会自动销毁$destroy本身时,相关的控制器被删除.
Ren*_*des 53
使用$ rootScope.$ broadcast和$ scope.$ on进行PubSub通信.
另请参阅此文章:AngularJS - 在控制器之间进行通信
小智 42
由于defineProperty存在浏览器兼容性问题,我认为我们可以考虑使用服务.
angular.module('myservice', [], function($provide) {
$provide.factory('msgBus', ['$rootScope', function($rootScope) {
var msgBus = {};
msgBus.emitMsg = function(msg) {
$rootScope.$emit(msg);
};
msgBus.onMsg = function(msg, scope, func) {
var unbind = $rootScope.$on(msg, func);
scope.$on('$destroy', unbind);
};
return msgBus;
}]);
});
Run Code Online (Sandbox Code Playgroud)
并在控制器中使用它,如下所示:
控制器1
function($scope, msgBus) {
$scope.sendmsg = function() {
msgBus.emitMsg('somemsg')
}
}
Run Code Online (Sandbox Code Playgroud)控制器2
function($scope, msgBus) {
msgBus.onMsg('somemsg', $scope, function() {
// your logic
});
}
Run Code Online (Sandbox Code Playgroud)num*_*ati 15
实际上使用发射和广播是低效的,因为事件在范围层次结构中上下波动,这很容易降级为复杂应用程序的性能瓶装.
我建议使用服务.以下是我最近在我的一个项目中实现它的方法 - https://gist.github.com/3384419.
基本思路 - 将pubsub/event bus注册为服务.然后在需要订阅或发布事件/主题的地方注入eventbus.
小智 14
使用服务中的get和set方法,您可以非常轻松地在控制器之间传递消息.
var myApp = angular.module("myApp",[]);
myApp.factory('myFactoryService',function(){
var data="";
return{
setData:function(str){
data = str;
},
getData:function(){
return data;
}
}
})
myApp.controller('FirstController',function($scope,myFactoryService){
myFactoryService.setData("Im am set in first controller");
});
myApp.controller('SecondController',function($scope,myFactoryService){
$scope.rslt = myFactoryService.getData();
});
Run Code Online (Sandbox Code Playgroud)
在HTML HTML中,您可以像这样检查
<div ng-controller='FirstController'>
</div>
<div ng-controller='SecondController'>
{{rslt}}
</div>
Run Code Online (Sandbox Code Playgroud)
关于原始代码 - 您似乎希望在范围之间共享数据.要在$ scope范围内共享数据或状态,文档建议使用服务:
我实际上已经开始使用Postal.js作为控制器之间的消息总线.
作为消息总线,如AMQP样式绑定,邮政可以集成w/iFrames和Web套接字的方式,以及更多的东西,它有很多好处.
我用装饰器来设置邮政$scope.$bus......
angular.module('MyApp')
.config(function ($provide) {
$provide.decorator('$rootScope', ['$delegate', function ($delegate) {
Object.defineProperty($delegate.constructor.prototype, '$bus', {
get: function() {
var self = this;
return {
subscribe: function() {
var sub = postal.subscribe.apply(postal, arguments);
self.$on('$destroy',
function() {
sub.unsubscribe();
});
},
channel: postal.channel,
publish: postal.publish
};
},
enumerable: false
});
return $delegate;
}]);
});
Run Code Online (Sandbox Code Playgroud)
这是关于该主题的博客文章的链接...
http://jonathancreamer.com/an-angular-event-bus-with-postal-js/
| 归档时间: |
|
| 查看次数: |
208473 次 |
| 最近记录: |