Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular http returns $$state object

I have the following factory defined:

angular.module("account").factory("users",["$http",
    function(a){
      return {
         getUser: function(){
            return a.get("/user/me").then(function(r){
                return r.data;
            });
        }
    };
  }
]);

And my controller:

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        a.user = u.getUser();
        console.log(a.user);
}]);

Here's the console.log:

 d {$$state: Object, then: function, catch: function, finally: function} $$state: Object status: 1 value: Object user: Object__v: 0 _id: "54c1fg29f36e117332000005" temp: "1ce3793175e0b2548fb9918385c2de09"  __proto__: Object __proto__: Object __proto__: Object __proto__: Object

The above code is returning a state object instead of the user object. But from the log, the state object has the user object within value. How do i get the user object? Or am i doing this completely wrong?

I know the other way is to return the $http.get and call the then() method within controller. But I'll be using the user object frequently and if i'm calling the then() method in controller, its almost same as using the $http.get in controller instead of the factory.

like image 262
wdphd Avatar asked Jan 26 '15 08:01

wdphd


2 Answers

JavaScript I/O is usually, including in this case asynchronous. Your getUser call returns a $q promise. In order to unwrap it you have to chain to it and then unwrap it as such:

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        u.getUser().then(function(user){
            a.user = user;
            console.log(a.user);
        });
}]);

If you're using routing you might also want to look into the resolve option in the route. Also see this related question.

like image 83
Benjamin Gruenbaum Avatar answered Nov 12 '22 04:11

Benjamin Gruenbaum


angular.module("account").factory("users",["$http",
    function(a){
      var factObj = {
         user: null,
         getUser: function(){
            return a.get("/user/me").then(function(r){
                factObj.user = r.data;
            });
        }
      factObj.getUser();

      return factObj;
    };
  }
]);

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        a.userService = u;
}]);

In your view

<div ng-controller="TestCtrl as test">{{test.userService.user}}</div>

Edits based on comments, true this would not work with the controller or view as you probably had them, but this pattern works well and removes the need to have .then in every controller that may re-use the data.

Typically storing your model in the factory or service that deals with fetching the data makes for an easier path to getting the data into every view where you need it. Down side here is you'd be fetching the user when this factory is referenced instead of explicitly firing the getUser function from the controller. If you want to get around that you can store the promise from the first time it's requested in the getUser function and just return that promise for all subsequent calls if it's already set, this way you can call getUser multiple times without repeating the API request.

like image 42
shaunhusain Avatar answered Nov 12 '22 02:11

shaunhusain