Lucas Raines
Lucas Raines

Reputation: 1315

Return a value from AngularJS API service to controller

If I have a service that looks like this:

app.factory('User', function($http, User) {
    var User = function(data) {
        angular.extend(this, data);
    };
    User.prototype.create = function() {
        var user = this;

        return $http.post(api, user.getProperties()).success(function(response) {
            user.uid = response.data.uid;
        }).error(function(response) {

        });
    };

    User.get = function(id) {
        return $http.get(url).success(function(response) {
            return new User(response.data);
        });
    };

    return User;
});

How do I, in a controller, get the User that was created in the get() function?

Currently what I have is:

app.controller('UserCtrl', function($scope, User) {
    $scope.user = null;

    User.get($routeParams.rid).success(function(u) {
        $scope.user = new User(u.data);
    });
});

The issue is that the UserCtrl is getting the api response, not the value returned from the success() in the factory. I'd prefer to be making the new user in the factory, as opposed to passing the api response to the controller.

Upvotes: 1

Views: 3769

Answers (3)

Siva Dorai
Siva Dorai

Reputation: 63

Had similar problem, when i had 'response.data' passed to def.resolve, from controller it throws as undefined. So passed the response directly and it worked.

var def = $q.defer();
$http.get('http://localhost:3000/api/services')
      .success(function (response) {
          ***def.resolve(response);***              
      })
      .error(function (error) {              
          def.reject(error);
      });
      return def.promise;

Upvotes: 0

Rathish Cholarajan
Rathish Cholarajan

Reputation: 890

Edit: May 5th 2015

I learnt about the deferred anti-pattern while trying to answer this question.

So we can avoid using $q.defer() and use the following code to achieve the same result.

Service

User.get = function(id) {
    return $http.get(url).then(function(response) {
        return new User(response.data);
    });
};

Controller

User.get($routeParams.rid).then(function(u) {
    $scope.user = u;
});

Original Answer below:

I think what you are looking for is the $q service which allows you to do some post processing on the response from the asynchronous $http service and then return it to the controller as a promise. Check out the documentation here https://docs.angularjs.org/api/ng/service/$q

So inject the $q service in your factory and change your User.get function like below.

User.get = function(id) {
    var deferred = $q.defer();

    $http.get(url).success(function(response) {
        deferred.resolve(new User(response.data));
    }).error(function(error) {
        deferred.reject(error);
    });

    return deferred.promise;
};

And then in your controller you can do

User.get($routeParams.rid).then(function(u) {
    $scope.user = u;
}, function(error) {
    //log error
});

Upvotes: 5

Ed Knowles
Ed Knowles

Reputation: 1925

I think your returns are a bit messed up. Personally I would have written it something like this

app.factory('User', function ($http) {

    var user = {
        new: function (data) {
            return $http.post(api, data);
        },
        get: function (id) {
            $http.get(url).success(function (response) {
                return user.new(response.data);
            });
        }
    };

    return user;

});

Then from inside your controller..

app.controller('UserCtrl', function($scope, User) {
    $scope.user = null;

    User.get($routeParams.rid).success(function(u) {
        $scope.user = u.data;
    });
});

Upvotes: 0

Related Questions