Как я могу получить набор отложенных объектов в одной области для включения в дайджест другой области в AngularJS?

Народ, у меня проблема. Я использую AngularJS и настраиваю отложенный объект внутри определения службы Angular:

angular.module('myServices', []).
  service('Brand', function($rootScope, $q){
    var service = {
        getNext: function() {
            var deferred = $q.defer();

            setTimeout(function() {
                deferred.resolve('foo');
            }, 2000);

            return deferred.promise;
        }
    };

    return service;
});

Служба используется в моем контроллере:

angular.module({
    controllers: {
        brand: function($scope, Brand) {
            $scope.changeBrand = function() {
                $scope.brand = Brand.getNext();
            }
        }
    }
}, ['myServices]);

И, наконец, представление ждет, пока обещание будет разрешено, а затем отображает его:

<a ng-click="changeBrand()" id="changeBrand">Change</a>
<p ng-bind="brand"></p>

Проблема в том, что хотя промис и обрабатывается, и хотя представление прекрасно ждет, пока промис будет разрешен и показывает результат, оно не делает этого немедленно. Он появляется только тогда, когда я добавляю этот код и нажимаю ссылку:

// View:
<a ng-click="apply()">Apply</a> 

// Controller:
$scope.apply = function() {
    $scope.$apply();
};

Существует ли часть дайджеста, в котором живет обещание, отдельно от дайджеста, который запускается при изменении области видимости/контроллера? Как я могу заставить дайджест автоматически запускаться в области представления/контроллера при разрешении отложенного?

Спасибо!


person Mark Stickley    schedule 21.11.2012    source источник


Ответы (1)


Несколько дней назад у меня была такая же проблема при реализации ленивых контроллеров с обещаниями. Когда вы посмотрите на документацию о routeProvider, вы найдете пример, который использует службу $timeout с обещаниями (https://github.com/angular/angular.js/blob/master/src/ng/route.js#L186). Реализация $timeout использует $rootScope.$apply() для вызова жизненного цикла и обновления привязок (насколько мне известно, она вызывает все функции грязной проверки — так привязки работают в Angular). Итак, решение моей проблемы (и, я думаю, и вашей) заключалось в добавлении $rootScope.$apply() после resolve(), например:

 setTimeout(function() {
            deferred.resolve('foo');
            $rootScope.$apply();
        }, 2000);
person matys84pl    schedule 21.11.2012
comment
Вы должны использовать $timeout вместо setTimeout с $apply. Это то же самое, но чище и угловатее. Так что это будет $timeout(function() { deferred.resolve('foo'); }, 2000); - person Andrew Joslin; 22.11.2012
comment
Вы правы, я также указал на метод $timeout и на то, что он реализует сам $apply, но я думаю, что в его примере setTimeout() использовался только для имитации асинхронной природы промисов. - person matys84pl; 22.11.2012
comment
Да, вы правы - это было :) Но спасибо, Энди, за то, что обратил внимание на это для всех, кто ищет это решение. - person Mark Stickley; 27.11.2012