2014-10-24 2 views
2

Я пытаюсь инкапсулировать события в службе, чтобы внедрить механику для подписки/отмены подписки слушателей, когда область действия контроллера уничтожена. . Это потому, что я использую rootScope $ на следующий образом:Как инкапсулировать отдельные и временные события в службе?

if(!$rootScope.$$listeners['event']) { 
    $rootScope.$on('event', function(ev, data){ 
     // do some... 
    }); 
} 

или

$scope.$on('$destroy', function(ev, data){ 
    // unsubscribe the listener 
}); 

Так что я просто нужен один слушатель этого события, нужно удалить существующий слушатель, когда контроллер больше не жив, потому что функция, которую я зарегистрировал ранее, все еще запускается.

Так что мне нужно реализовать прослушиватель событий $ destroy на моем контроллере, чтобы уничтожить слушателя при уничтожении области, но я не хочу делать этот код каждый раз, когда я создаю событие. Вот почему я хочу создать сервис, где я собираюсь инкапсулировать события.

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

Это может быть сделано с помощью $ rootScope вместо моих собственных методов, но инкапсулирования $ на $ и испускать из $ rootScope, но в конце концов я буду иметь один и тот же вопрос здесь.

Так вот мои вопросы:

  1. Это хорошая практика, чтобы передать значение реф область к службе?
  2. В чем смысл уничтожения $$? когда это верно, означает, что угловой JS не имеет внутренних ссылок на экземпляр?
  3. Должен ли я сделать scope = null в моей службе, чтобы GC удалял объект или выполнял angularJS с явным удалением?
  4. Есть ли лучший способ сделать то, что я хочу?
+1

что с "!!!" ? – dandavis

+0

@ dandavis Я использую === во всем проекте, поэтому я использую !! на литье фальшивых ценностей, здесь меня бросились и снова отрицали .. Я знаю .. просто! хорошо – rahpuser

ответ

3

То, что вы пытаетесь выполнить, это, в основном, автобус события.
Вы также очень хорошо описали, что не так с текущей реализацией. Другой способ подойти к проблеме - украсить $ rootScope своей шиной (или любой другой шиной событий, если на то пошло). Вот как:

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

Учитывая реализацию следующих $$ шины (хранится основной для простоты):

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

Теперь все, что вам нужно сделать, это подписаться или публиковать события. Отписки будет происходить автоматически (когда $ Прицел уничтожен):

$scope.$bus.subscribe({ 
    name: 'test', callback: function (data) { 
     console.log(data); 
    } 
    }); 

А потом опубликовать событие:

$scope.$bus.publish('test', {name: "publishing event!"}); 

важный момент состоит в том, что события сами подписаны для каждого отдельного $ scope, а не $ rootScope. Вот как вы «знаете», какой $ scope выпустить.

Я думаю, что это отвечает на ваш вопрос. Имея это в виду, вы, очевидно, можете сделать этот механизм очень сложным (например, прослушиватель событий контроллера, выпущенный при маршрутизации, автоматически отмените подписку на определенные события и т. Д.). Удачи!

** Это решение принято в форме Here, в котором используется другой каркас шины (другой, то есть тот же самый).

+0

спасибо! это именно то, что мне нужно, это решение просто идеально. – rahpuser

Смежные вопросы