How can I get a deferred object set in one scope to be included in the digest of another scope in AngularJS?

StackOverflow https://stackoverflow.com/questions/13500051

Question

Folks, I have a problem. I'm using AngularJS and I am setting up a deferred object inside an Angular service definition:

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

The service is used in my controller:

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

And finally the view waits for the promise to be resolved and then displays it:

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

The trouble is that although the promise is being resolved and although the view does just fine waiting for the promise to be resolved and showing the result, it doesn't do it immediately. It only shows up when I add this code and click the link:

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

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

Does the part of the digest that the promise lives in exist separately from the digest that runs when the view/controller's scope is changed? How can I get the digest to run on the view/controller's scope automatically when the deferred resolves?

Thanks!

Was it helpful?

Solution

Few days ago I had the same issue while implementing lazy controllers with promisses. When you take a look at the documentation about routeProvider there is a sample that uses $timeout service with promises (https://github.com/angular/angular.js/blob/master/src/ng/route.js#L186). $timeout implemation uses $rootScope.$apply() to call the lifecycle and refresh the bindings (AFAIK it calls all dirty check functions - it's how bindings work in Angular). So the solution to my problem (and I think also yours) was adding $rootScope.$apply() after the resolve(), like this:

 setTimeout(function() {
            deferred.resolve('foo');
            $rootScope.$apply();
        }, 2000);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top