Search code examples
angularjsdeferredangularjs-scopeangularjs-service

AngularJS deferred specific behavior inside the scope


Assume that we have a bit of html like that:

<button
  id="my-login-button"
  ng-hide="loggedIn"
  ng-click="login()">Log me in!</button>

Also we have a JavaScript:

// controller.js
$scope.login = function () {
    API.login()
      .then(function () {
        console.log('login promise resolved');
      });
};

// service.js
app.factory('API', ['$q', '$timeout', function ($q, $timeout) {
  return {
    login: function () {
      var login = $q.defer();

      // async login
      VK.Auth.login(
        function () {
          // login.resolve();       // doesn't work without $timeout()
          $timeout(login.resolve);  // works as it should
        },
        VK.access.FRIENDS | VK.access.AUDIO
      );

      return login.promise;
    }
  };
}]);

This piece of code works properly, but the mysterious part is near the $timeout() function. Why I should wrap my resolving with it? Why code doesn't work as expected without it?

I don't do something with scope variables, I'm just consoling. And without $timeout it will be called with next digest...

As for me it have no sense, if I need to change scope props, I will wrap everything in $apply.

Could anyone explain why usual deferred behavior became mysterious one?

P.S. I've solved my issue with $timeout after reading this question answers.


Solution

  • In AngularJS promise results are propagated asynchronously, inside a $digest cycle. So, the results of then() are not propagated until the next digest cycle, which never comes without a $timeout or $http or $apply to trigger one.

    See also Promise callback not called in Angular JS