Lucas Raines Lucas Raines - 2 months ago 10
AngularJS Question

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.

Answer

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
});
Comments