user3052526
user3052526

Reputation: 681

Angularjs $http promise defer

I am working with the $http in 1.4.7.

I need to separate my controllers from any $http requests. So i created a service as follows:

app.service('MyService', function($http, $q, $rootScope) {

  this.getcustomers = function() {
    var deferred = $q.defer();
    $http({
      method: 'GET',
      url: 'http://call/to/rest/api'
    }).then(function successCallback(response) {
      deferred.resolve(response.data);
    }, function errorCallback(response) {
      deferred.reject(error);
    });
    return deferred.promise;
  };

});

Then in my controller i call that service as follows:

app.controller('registerationCtrl', ['$scope', '$http', 'MyService', '$location', function($scope, $http, MyService, $location) {
  $scope.custlst = [];

  $scope.getcustomers = function() {

    var x = MyService.getcustomers().then(function(data) {
      $scope.custlst = data;
    }, function(err) {
      alert(err);
    });

  }


}]);

Now, the above is not working it gives me a ReferenceError of error now defined and points to the errorCallback function in the service.

Question 1: What is wrong with the script? Question 2: Is it important to use $q? Keeping in mind that the server can be slow.

Thanks.

Upvotes: 1

Views: 5690

Answers (3)

New Dev
New Dev

Reputation: 49590

As I mentioned in comments, the error you're seeing is due to the error variable not being declared inside the errorCallback function.

As for $q - no need to use it, although the way you implemented would still work. To make it simpler and to follow the intent of promises (i.e. that they allow async code to mirror code composition of sync code) it's better to return the original promise of $http (or of $http().then()):

this.getcustomers = function() {
  return $http({
      method: 'GET',
      url: 'http://call/to/rest/api'
    })
    // pre-process the HTTP response and return the data
    .then(function(response) {
      return response.data;
    })
    // If needed, create a custom error to hide HTTP details from caller
    // otherwise, don't include .catch - the original error will "bubble up"
    .catch(function(error) {
      return $q.reject({
        msg: "something broke"
      });
    });
};

Then, the client can be used as you intended:

MyService.getcustomers()
  .then(function(data) {
    $scope.customers = data;
  })
  .catch(function(error) {
    console.log(error.msg);
  })

Upvotes: 1

Freezystem
Freezystem

Reputation: 4874

Actually you don't need to use $q to create a promise. $http do it for you already, so you can simply do :

app.service('MyService', function($http) {
  this.getcustomers = function() {
    return $http.get({
      method: 'GET',
      url: 'http://call/to/rest/api'
    });
  };
});

Then you can chain your MyService.getcustomers with .then() easily and handle the response like that :

MyService.getcustomers.then(
  function(data) {
    //do something with data
  },
  function(error) {
    //do something with error
  }
);

I think you should take a look at this post I you want to better understand how promises works and behaves.

EDIT: update deprecated call to $http.

Upvotes: 3

Well, in the AngularJS docs: https://docs.angularjs.org/api/ng/service/$http

Deprecation Notice The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.

You don't need to use the $q promise.

As you're using GET request, you might use the shortcut method to perform GET request.: $http.get();.

So, you might try something like this:

MyService service: Only you need the $http service.

app.service("MyService", ["$http", function ($http) {
    this.getcustomers = function () {
        return $http.get("http://call/to/rest/api");
    };
}]);

The service above lets you use the service, in any controller. So, any controller can performs others action by using the same data.

registerationCtrl controller: You need the $scope, MyService and location services.

    app.controller("registerationCtrl", ["$scope", "MyService", "$location", function ($scope, MyService, location) {
        $scope.custlst = [];

        $scope.getcustomers = function () {
            MyService.getcustomers().then(function (response) {
                $scope.custlst = response.data;
            }, function (err) {
                alert(err);
            });
        };
    }]);
}]);

Upvotes: 1

Related Questions