1

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.

3 Answers 3

5

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
});
Sign up to request clarification or add additional context in comments.

1 Comment

I agree that this is a cleaner method.
0

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

8 Comments

This is what I did above. It doesn't work. What happens is that the data returned from the promise is what is passed to the UserCtrl
I've just realised what you've done, by using new User you're creating an instance of that factory and returning it. Unless you have another factory called User. If you do can you put up some more code?
I realized I made a typo above. app.factory('User') returns User. I could put more code up, but it's the same as above. Just more functions. Some are .prototype, others, like get, aren't.
I assumed that was a typo :) my point is do you have a function that creates a user? maybe something like User.prototype.create...?
Added example of User.prototype.create.
|
0

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.