Sam
Sam

Reputation: 15771

Correct use of Promises in Angular

I am trying to get my head wrapped around the concept of Promises in AngularJS.

Is the following code on the right track? And could someone explain the PlateCheckService.checkPlate method and why if I don't return the promise? return $http.post().then why the inner return of the object with the message and alertClass does not work? I think it is a chained/inner promise?

/// <reference path="angular.js" />
(function () {
"use strict"

var app = angular.module('cs');

app.service('PlateCheckService', ['$http', function ($http) {
    return {
        checkPlate: function (plateNumber) {
            return $http.post('PlateCheck/Index', {
                plateNumber: plateNumber
            }).then(function (response) {
                return {
                    message: response.data.VehicleAtl === null ? 'Clean' : 'Hot',
                    alertClass: response.data.VehicleAtl === null ? 'alert-success' : 'alert-danger'
                }
            });
        }
    }
}]);

app.controller('PlateCheckCtrl', ['$scope', 'PlateCheckService', function ($scope, PlateCheckService) {
    var plateCheck = {
        plateNumber: '',
        message: '',
        alertClass: '',
        checkPlate: function (plateNumber) {
            var _this = this;

            PlateCheckService.checkPlate(plateNumber).then(function (response) {
                _this.message = response.message;
                _this.alertClass = response.alertClass;
            });
        }
    };

    $scope.plateCheck = plateCheck;
}]);

}());

Upvotes: 0

Views: 297

Answers (1)

Davin Tryon
Davin Tryon

Reputation: 67296

Yes, it is because of chained promises. Remember that a call to then will return a promise before the function it encloses is called.

So, your call here: PlateCheckService.checkPlate(plateNumber) will expect to return a chained promise. However, your service's then enclosed function is not returning a promise. Therefore, it will fail to have a then function to chain once it is resolved.

You can visualize this with the following psuedo code:

$http.get('url')
    .then(function(response) {
        return aPromise;
    })
    .then(function(aPromiseResponse) {
        return bPromise;
    })
    .then(function(bPromiseResponse) {
        return cPromise;
    })
    .then(function(cPromiseResponse) {
        // when scope is available
        $scope.bindToMe = cPromiseResponse.value;
    });

If you want to add functionality to a promise chain in a service, then the wrapped promise function needs to return a promise as well.

The easiest way I have found to do this is with $q.when. $q.when will wrap the object in a promise if the object is not a promise. If an object is already available (like in your case), then $q.when will instantly resolve. Documentation for $q.when is here.

So, you should be able to get your code to work by using this in the service:

return $q.when({
          message: response.data.VehicleAtl === null ? 'Clean' : 'Hot',
          alertClass: response.data.VehicleAtl === null ? 'alert-success' : 'alert-danger'
       });

Upvotes: 1

Related Questions