Take the 2-minute tour ×

I'm looking into chaining promises to populate my scope, and then having the scope automatically update the dom.

I'm running into problems with this though.. If I call "then" on an already resolved promise, it creates a new promise (that will call the success function asynchronously but almost immediately). I think the problem is that we've already left the digest cycle by the time the success function is called, so the dom never updates.

Here is the code:

<div ng-controller="MyCtrl">
    Hello, {{name}}! <br/>
    <button ng-click="go()">Clickme</button><br/>


function MyCtrl($scope, $q) {
    var data = $q.defer();    
    setTimeout(function() {$scope.$apply(data.resolve("Some Data"))}, 2000);
    var p = data.promise;

    $scope.name = p.then(angular.uppercase);
    $scope.name2 = p.then(function(x) { return "Hi "+x;});
    $scope.go = function() {
            $scope.name3 = p.then(function(x) { 
                // uncomment this to make it work:
                return "Finally: "+x;


Is there some way to make this work without calling $apply every time I chain promises?

share|improve this question
Why are you putting a promise in the go() function? –  Plynx Feb 2 '13 at 1:38
There is a promise there because I'm running code on the result of the original "p" promise. I want the code to run correctly whether or not "p" has been resolved... hence we create a new promise from the old promise. –  Karl Zilles Feb 4 '13 at 19:48
add comment

1 Answer

up vote 7 down vote accepted

To quote @pkozlowski.opensource:

In AngularJS the results of promise resolution are propagated asynchronously, inside a $digest cycle. So, callbacks registered with then() will only be called upon entering a $digest cycle.

So, when the button is clicked, we are in a digest cycle. then() creates a new promise, but the results of that then() will not be propagated until the next digest cycle, which never comes (because there is no $timeout, or $http, or DOM event to trigger one). If you add another button with ng-click that does nothing, then click that, it will cause a digest cycle and you'll see the results:

<button ng-click="">Force digest by clicking me</button><br/>

Here's a fiddle that does that.

The fiddle also uses $timeout instead of setTimeout -- then $apply() isn't needed.

Hopefully it is clear when you need to use $apply. Sometimes you do need to call it manually.

share|improve this answer
Okay, I think I've got my head around it now. I ended up rewriting my question and code so many times that I got about 80% of the way there myself. It kind of seems too bad that we have to manually force digest for resolving promises, but it could still be interesting to code that way. –  Karl Zilles Feb 4 '13 at 19:57
add comment

Your Answer


