如何封装在服务单和时间的事件? [英] How to encapsulate single and temporal events in a service?
问题描述
我想封装在一个服务事件,以便实现机械订阅/退订听众当一个控制器的范围被破坏。这是因为我一直在使用rootScope通过以下方式上$:
如果(!$ rootScope。$$听众['事件']){
$ rootScope。在$('事件',函数(EV,数据){
// 做一些...
});
}
或
$范围。在$('$破坏',函数(EV,数据){
//退订监听器
});
所以我只需要这个事件的一个监听器,我需要删除现有的监听器当控制器不再活着,因为我先前注册的功能仍然被触发。
所以,我需要实现一个$破坏事件监听我的控制器上,破坏侦听器时的范围被破坏,但我不希望每次我创建活动时做code。
这就是为什么我要创造我要去哪里来封装事件的服务。
angular.module(核心)工厂('事件',[
功能(){
变种服务= {};
service.events = {};
service.on =功能(范围,事件ID,回调){
范围。在('$破坏',函数(EV,其他$){
//退订
});
service.events [事件ID] =回调;
//范围= NULL;我猜 ?
};
service.emit =功能(事件ID,数据){
如果(service.events [事件ID])
service.events [EVENTID](数据);
其他
返回新错误('事件未订阅);
};
退换货服务;
}
]);
这可以用做 $ rootScope ,而不是我自己的方法,但在封装和$发出的$ $ rootScope ,但最后我将有同样的问题在这里。
因此,这些都是我的问题:
- 是一个很好的做法,范围参考值传递给服务?
- 什么是$$意思摧毁?当这是真的意味着angularJS有实例内部没有参考?
- 我应该做的范围 =空在我的服务,让GC删除对象还是angularJS处理一个明确的删除?
- 有没有更好的方法做我想要什么?
你所要完成的主要是一个事件总线。
您也已经描述得非常好什么是错的当前实现。
一种不同的方式来处理这个问题是装饰$ rootScope与总线(或任何其他事件总线为此事)。方法如下:
的app.config(函数($提供){
$ provide.decorator('$ rootScope',['$代表,$$总线,函数($代表,$$总线){
Object.defineProperty($ delegate.constructor.prototype,'$公交',{
得到:函数(){
VAR自我=这一点; 返回{
订阅:功能(){
VAR子= $$ bus.subscribe.apply($$总线参数); 自我。在$('$灭',
功能(){
的console.log(退订!);
sub.unsubscribe(); });
}, 发布:$$ bus.publish
};
},
枚举:假的
}); 返回$代表;
}]);
});
考虑以下$$总线实施(保持基本为简单起见):
app.factory('$$总线,函数(){
VAR API = {};
VAR的事件= {}; api.subscribe =函数(事件){
如果(!events.hasOwnProperty(event.name)){
事件[event.name] = [事件];
}其他{
事件[event.name] .push(事件);
}
返回{
退订:功能(){
api.unsubscribe(事件);
}
}
}; api.publish =功能(eventName的数据){
如果(events.hasOwnProperty(eventName的)){
的console.log(eventName的); angular.forEach(事件[eventName的]功能(用户){
subscriber.callback.call(此,数据);
});
}
}; api.unsubscribe =函数(事件){
如果(events.hasOwnProperty(event.name)){
事件[event.name] .splice(事件[event.name] .indexOf(事件),1);
如果(事件[event.name]。长度== 0){
删除事件[event.name]
}
}
}; 返回API;
});
现在你需要做的就是订阅或发布事件。退订将自动发生时($范围破坏):
$范围。$ bus.subscribe({
名称:测试,回调:功能(数据){
的console.log(数据);
}
});
和以后发布事件:
$ $范围bus.publish:;('测试',{名发布事件!})
这是重要点提出的是,事件本身所订阅的每个$范围,而不是在$ rootScope。那你是怎么知道其中价值范围发布。
我觉得这回答你的问题。考虑到这一点,你可以明显地使这个机制复杂得多(如控制器事件侦听器释放时路由的视图,自动退订只对某些事件等)。
祝你好运!
**此解决方案是采取形式这里这使用不同的总线架构(其他然后,它是相同的)。
I'm trying to encapsulate the events in a service in order to implement a mechanics to subscribe / unsubscribe the listeners when a controller's scope is destroyed. This because I have been using the rootScope.$on in the following way:
if(!$rootScope.$$listeners['event']) {
$rootScope.$on('event', function(ev, data){
// do some...
});
}
or
$scope.$on('$destroy', function(ev, data){
// unsubscribe the listener
});
So I just need one listener of this event, I need to delete the existing listener when the controller is no longer alive, because the function I registered earlier is still being triggered.
So I need to implement a $destroy event listener on my controller, to destroy the listener when the scope is destroyed, but I don't want to do that code each time I create an event. That's why I want to create a service in where I'm going to encapsulate the events.
angular.module('core').factory('event', [
function() {
var service = {};
service.events = {};
service.on = function(scope, eventId, callback) {
scope.$on('$destroy', function(ev, other){
//unsubscribe
});
service.events[eventId] = callback;
// scope = null; I guess ?
};
service.emit = function(eventId, data){
if (service.events[eventId])
service.events[eventId](data);
else
return new Error('The event is not subscribed');
};
return service;
}
]);
This could be done using $rootScope instead of my own methods but encapsulating the $on and $emit of $rootScope, but at the end I'll have the same issue here.
So these are my questions:
- Is a good practice to pass the scope ref value to a service?
- What is the meaning of $$destroyed? when this is true means that angularJS has no internal references to the instance?
- Should I do a scope = null in my service to let GC delete the object or does angularJS handle an explicit delete?
- Is there a better way to do what I want?
What you are trying to accomplish is basically an event bus.
You have also described very well what is wrong with the current implementation.
A different way to approach the problem is to decorate the $rootScope with your bus (or any other event bus for that matter). Here is how:
app.config(function ($provide) {
$provide.decorator('$rootScope', ['$delegate', '$$bus', function ($delegate, $$bus) {
Object.defineProperty($delegate.constructor.prototype, '$bus', {
get: function () {
var self = this;
return {
subscribe: function () {
var sub = $$bus.subscribe.apply($$bus, arguments);
self.$on('$destroy',
function () {
console.log("unsubscribe!");
sub.unsubscribe();
});
},
publish: $$bus.publish
};
},
enumerable: false
});
return $delegate;
}]);
});
Considering the following $$bus implementation (kept basic for simplicity):
app.factory('$$bus', function () {
var api = {};
var events = {};
api.subscribe = function (event) {
if (!events.hasOwnProperty(event.name)) {
events[event.name] = [event];
} else {
events[event.name].push(event);
}
return {
unsubscribe: function () {
api.unsubscribe(event);
}
}
};
api.publish = function (eventName, data) {
if (events.hasOwnProperty(eventName)) {
console.log(eventName);
angular.forEach(events[eventName], function (subscriber) {
subscriber.callback.call(this, data);
});
}
};
api.unsubscribe = function (event) {
if (events.hasOwnProperty(event.name)) {
events[event.name].splice(events[event.name].indexOf(event), 1);
if (events[event.name].length == 0) {
delete events[event.name];
}
}
};
return api;
});
Now all you have to do is subscribe or publish events. The unsubscribe will take place automatically (when the $scope is destroyed):
$scope.$bus.subscribe({
name: 'test', callback: function (data) {
console.log(data);
}
});
And later on publish an event:
$scope.$bus.publish('test', {name: "publishing event!"});
An important point to make is that the events themselves are subscribed to each individual $scope and not on the $rootScope. That is how you "know" which $scope to release.
I think it answers your question. With that in mind, you can obviously make this mechanism much sophisticated (such as controller event listener released when a view routed, unsubscribe automatically only to certain events, etc.). Good luck!
** This solution is taken form Here which uses a different bus framework (other then that it is the same).
这篇关于如何封装在服务单和时间的事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!