2

There is related question about processing $http in a service, but I wanted to elaborate slightly. I would like my controller to be able to execute service calls using API similar to the Angular $http API:

$scope.login = function(user) {
  securityService.login(user).success(function(data) {
    $scope.data = data;
  }).error(function(data) {
    $scope.error = data;
  });
};

That's a nice readable API. On the surface, all I would need to do in the service API is:

return {
  name : 'User Service',
  login : function(user) {
    return $http.post("/api/login", user);
  }
};

Great, it returns the promise and the success and error messages come with. But... What if I want to deal with the success and failure cases in the service? I want to maintain the nice, readable service API. In this case, maybe I'd want to preserve the user so that I could expose methods like securityService.currentUser() or `securityService.isLoggedIn()'.

I tried the $http.post().then(...) promise API, but those return the entire HTTP response. Again, I want to isolate HTTP to the services and maintain a similar concrete callback API.

Community
  • 1
  • 1
andyczerwonka
  • 4,230
  • 5
  • 34
  • 57

2 Answers2

5

You could make your own promise in login using angular's $q:

var deferred = $q.defer(), 
    promise = deferred.promise;

$http.post("/api/login", user).success(...).error(...)

return promise;

Within the success/failure of the $http promise in your service, resolve/reject your deferred object.

Edit:

Expanding upon the $http.post:

$http.post("/api/login", user).success(function(data) {
  if (data == "foo") { // success case?
    deferred.resolve('you logged in!');
  } else {
    deferred.reject('something really bad happened!');
  }
})
wless1
  • 3,489
  • 1
  • 16
  • 12
1

I just ran a test case and it seems that if I return the promise from the service API like this:

return $http.post("/api/login", user).success(...).error(...)

I can also do the same in the controller:

service.login(user).success(...).error(...)

and both get called, the service first and the controller second. That's perfect!

andyczerwonka
  • 4,230
  • 5
  • 34
  • 57
  • Sure, promises can be chained. You'd want to make your own promise if you didn't want to expose your controller to the low-level details of what `$http` was returning, and instead return something cleaner from your API. – wless1 Jan 10 '13 at 19:22
  • One note to this: don't forget that `.success().error()` syntax is not supported by `$q`, and is emulated by `$http` (you can look at source code how promise is been extended). That means, that `$q` chaning feature can not work if you return promise form succcess/error's callbacks. I would suggest using `then(successCb, errorCb)` syntax - then you can return other promises from callback and get a quite fancy chainable workflow. – Valentyn Shybanov Jan 10 '13 at 20:43