Ingó Vals
Ingó Vals

Reputation: 4898

Why doesn't my $q resolve and promise work like I think it does?

I'm always having problems with $q

Here is an example where the .then is fired right away

    function doit() {
            var deferred = $q.defer();

            var modalInstance = $modal.open({
                template: '<p>this is modal</p><a ng-click="ok()">ok</a>',
                controller: function ($scope, $modalInstance) {
                    $scope.ok = function () {
                        $modalInstance.close();
                    };
                }
            });

            modalInstance.result.then(function () {
                console.log('ok');
                deferred.resolve();
            }, function () {
                console.log('Modal dismissed');
            });

            return deferred.promise;
        }

Elsewhere:

    $scope.service.doit().then(
                $scope.variable = 5
            );

http://jsfiddle.net/IngoVals/stqwanhm/

I got this in Fiddle when trying to model another similar setup where .then didn't fire at all. What is going on here?

Upvotes: 3

Views: 157

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074385

You're passing the value 5 into then here:

$scope.service.doit().then(
    $scope.variable = 5
);

That code runs like this:

  1. $scope.variable is assigned the value 5

  2. The result of the assignment expression (which is the assigned value, 5) is passed into then

Both of those things happen right away, when you call then. They don't wait for the promise to be resolved.

You wanted to pass a function into then instead, and have the function set the variable:

$scope.service.doit().then(function() {
    $scope.variable = 5
});

Now you're passing in a function. The code in the function isn't run until it's called, which it will be later when the promise is resolved.

Updated Fiddle

The good news and bad news is that this is going to get a lot more concise as of ES6, because ES6 introduces "fat arrow" functions:

$scope.service.doit().then(() => $scope.variable = 5);

That also creates a function and passes it into then (on an ES6-enabled engine).

I say this is both good news and bad news because it's nice and concise (good!), and also very easy to miss when you're reading (bad!). :-)

Upvotes: 1

dfsq
dfsq

Reputation: 193261

It doesn't fire right away, it's just you update scope property outside of then callback. This code:

$scope.service.doit().then(
    $scope.variable = 5
);

is incorrect, it should be

$scope.service.doit().then(function() {
    $scope.variable = 5
});

Anothe problem is so called deferred anti-pattern. Avoid creating redundant deferred object:

function doit() {
    return $modal.open({
        template: '<p>this is modal</p><a ng-click="ok()">ok</a>',
        controller: function ($scope, $modalInstance) {
            $scope.ok = function () {
                $modalInstance.close();
            };
        }
    }).result.then(function () {
        console.log('ok');
    }, function () {
        console.log('Modal dismissed');
    });
}

Demo: http://jsfiddle.net/stqwanhm/2/

Upvotes: 2

Related Questions