понедельник, 22 декабря 2014 г.

AngularJS. Предлагаю дружить контроллерами.

Работая над очередным проектом с использованием AngularJS, столкнулся с необходимостью "подружить" контроллеры в приложении между собой. А поскольку приложение асинхронно, "дружить" они будут посредством событий.

Сразу давайте разъясним, что же значит "дружить". Имеется ввиду некая разновидность шаблона "подписчик-издатель", где каждый контроллер может быть как подписчиком, так и издателем.

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

Кроме того, поскольку в процессе работы приложения контроллеры могут быть созданы множество раз и в качестве шины планируется использовать глобальный по отношению к контроллеру объект, то при уничтожении контроллера необходимо удалять и его подписки:


var subscription = $rootScope.$on('component.evenName', function () {...});
$scope.$on('$destroy', subscription);


Дабы облегчить себе жизнь в разделе config приложения для $rootScope создадим метод, который будет делать это за нас:


var app = angular.module('MyApp', []);

app.config(['$provide', function ($provide) {
 $provide.decorator('$rootScope', ['$delegate', function ($delegate) {
        Object.defineProperty($delegate.constructor.prototype, '$eventBusOn', {
            value: function(name, listener){

                var subscription = $delegate.$on(name, listener);
                this.$on('$destroy', subscription);

                return subscription;                
            },
            enumerable: false
        });

        return $delegate;
    }]);
}]);


Пример использования:


app.controller('FirstController', ['$rootScope', function ($rootScope) {
 $rootScope.emit('FirstController.SaysHello', {message: 'Hello from FirstController'});
}]);

app.controller('SecondController', ['$scope', function ($scope) {
 $scope.$eventBusOn('FirstController.SaysHello', function (eventData) {
  console.log('SecondController caught event with message: ' + eventData.message);
 });
}]);

Комментариев нет:

Отправить комментарий