overlord overlord - 15 days ago 5
AngularJS Question

Same data is returned in AngularJS Promise Chaining

I want to make 3 API calls when my page is loaded to bring the necessary data.
My application is in AngularJS#1.5.8. I am able to bring the data separately in service, but for some reason, in the controller the data of first API call is returned all 3 times.
There is no dependency between the 3 API calls.

Here is my controller code

// app.module.js
(function () {

angular
.module('SomeAppName', [])
.controller('DDCtrl', DDCtrl);

DDCtrl.$inject = ['$scope', 'ApiService']

function DDCtrl($scope, ApiService) {

var vm = this;

vm.qddData = [];
vm.rddData = [];
vm.sddData = [];

activate();

function activate() {

ApiService.getNumberData('api/get.first.data.php')
.then(function (firstdata) {
console.log(firstdata);
vm.qddData = firstdata;
return ApiService.getNumberData('api/get.second.data.php');
})
.then(function (seconddata) {
console.log(seconddata); // logs firstdata instead of seconddata
vm.rddData = seconddata;
return ApiService.getNumberData('api/get.third.data.php');
})
.then(function (thirddata) {
console.log(thirddata); // logs firstdata instead of thirddata
vm.sddData = thirddata;
})
.catch(function (err) {
console.log(err.data);
});
}
}
})();


Here is my data service

// app.service.js
(function () {

angular
.module('SomeAppName')
.factory('ApiService', ApiService);

ApiService.$inject = ['$http', '$q'];

function ApiService($http, $q) {

var deferred = $q.defer();

return {
getNumberData: getNumberData
};

function getNumberData(dictUrl) {
return $http.get(apiUrl)
.then(getRequestComplete)
.catch(getRequestFailed);
}

function getRequestComplete(response) {
console.log(response.data); // here the data is logged correctly
deferred.resolve(response.data);
return deferred.promise;
}

function getRequestFailed(error) {
deferred.reject(error);
return deferred.promise;
}
}

})();

Answer

Threat is inside your ApiService, you are maintaining single defer object for all your http request which isn't correct. Rather I can say, you don't need to create your custom promise(its consider as anti-pattern). Just utilize promise return by $http.get & chain it via returning a data from its success callback.

Code

(function () {

  angular
    .module('SomeAppName')
    .factory('ApiService', ApiService);

  ApiService.$inject = ['$http', '$q'];

  function ApiService($http, $q) {
    //no need to create a custom defer object at all
    //var deferred = $q.defer();

    return {
      getNumberData: getNumberData
    };

    function getNumberData(dictUrl) {
      return $http.get(apiUrl)
        .then(getRequestComplete)
        .catch(getRequestFailed);
    }

    function getRequestComplete(response) {
      return response.data; //return a data to chain promise with success
    }

    function getRequestFailed(error) {
      return $q.reject(error); //reject to call error function of subsequent chain promise
    }
  }

})(); 
Comments