javascriptangularjsangularjs-serviceangularjs-resource

angularjs get the error message from the service to the controller


Factory that gets the rates using REST

.factory('rateResource', ['$resource', function ($resource) {
    return $resource('/rates/:currency/:effectiveDate', {
        currency: '@currency',
        effectiveDate: '@effectiveDate'
    });
}])

Service that calls the factory to get resource and retrieve the rates and also errors if there are any.

 .service('RateService', ['rateResource', '$rootScope',
    function (rateResource, $rootScope) {
        var self = this;

        self.rates = [];

        self.search = function (baseCurrency, effectiveDate) {
            self.rates = [];
            var error = null;
            self.baseCurrency = baseCurrency;
            self.effectiveDate = effectiveDate;
            if (baseCurrency) {
                rateResource.query({currency: baseCurrency, effectiveDate: effectiveDate})
                    .$promise.then(function (rates) {
                        if (rates) {
                            angular.forEach(rates, function (rate) {
                                rate.maintTs = $rootScope.formatTimestampToHHMMSS(rate.maintTs);
                                rate.editable = false;
                                self.rates.push(rate);
                            });
                            self.processing = false;
                        }
                    }, function (response) {
                        self.processing = false;
                        error = 'Processing failed due to '+response.status;
                        console.log(error);
                    })
                return {
                    rates: self.rates,
                    errors: error
                }
            }
        }
    }]);

Controller calls the service for rates.

.controller('RateController', ['RateService',
    function (rateService) {
        var self = this;

        self.baseCurrency = rateService.getBaseCurrency();
        self.effectiveDate = rateService.getEffectiveDate();
        self.rates = rateService.getRates();

        //make the call from the controller
        self.search = function () {
            var response = rateService.search(self.baseCurrency, self.effectiveDate.yyyyMMdd());
            self.rateRecords = response.rates;
            self.errors = response.errors;
        }
    }])

rates are showing up fine in the controller after the promise is fulfilled. However, upon receiving errors, they are not getting transferred from service to controller. ( I changed the REST URL to make service return a 404 response ). What am I doing wrong?


Solution

  • Currently you are returning asynchronous call response from outside of async function, you shouldn't do that technically. Asynchronous code always get there responses inside their promise/callback function.

    But in your case it is working because you are returning object with it reference. If you look at below code, return statement has carried self.rates object reference, so while returning even if it is blank, it is going to get updated value once self.rates gets filled up. So then you don't need to worry about the rates updation. But same thing for error would not work because it is of primitive datatype like var error = null, so when you are returning value it would be null(as async response haven't completed).

    return {
         rates: self.rates, //passed by reference
         errors: error //passed by primitive type
    }
    

    So for solving this issue you could also make the error to an object type, so that it reference will get passed with reference object, like var errors = [] & when error occur push the error message into that array using .push


    But I'd not recommend above way to go for, I'd rather take use of promise pattern and will maintain proper code call stack. Basically for that you need to return promise from search method & then put .then function to wait till resolve that function.

    Service

    .service('RateService', ['rateResource', '$rootScope',
        function(rateResource, $rootScope) {
          var self = this;
          self.rates = [];
          self.search = function(baseCurrency, effectiveDate) {
            self.rates = [];
            var error = null;
            self.baseCurrency = baseCurrency;
            self.effectiveDate = effectiveDate;
            if (baseCurrency) {
              return rateResource.query({
                currency: baseCurrency,
                effectiveDate: effectiveDate
              })
                .$promise.then(function(rates) {
                if (rates) {
                  angular.forEach(rates, function(rate) {
                    rate.maintTs = $rootScope.formatTimestampToHHMMSS(rate.maintTs);
                    rate.editable = false;
                    self.rates.push(rate);
                  });
                  self.processing = false;
                }
                //returning object from promise
                return {
                  rates: self.rates,
                  errors: error
                }
              }, function(response) {
                self.processing = false;
                error = 'Processing failed due to ' + response.status;
                console.log(error);
                //returning object from promise
                return {
                  rates: self.rates,
                  errors: error
                }
              })
            }
          }
        }
    ])
    

    Controller

    //make the call from the controller
    self.search = function() {
      var response = rateService.search(self.baseCurrency, self.effectiveDate.yyyyMMdd()).then(function() {
        self.rateRecords = response.rates;
        self.errors = response.errors;
      });
    }