AngularJS using $resource service. Promise is not resolved by GET request
Asked Answered
B

4

28

Let's say a service like this:

   services.factory('User', function($resource){
        return $resource('/rest/usersettings/:username', {}, {
            get:    {method: 'GET'},
            update: {method: 'POST'}
        });
    });

So it is supposed to be used like this:

        scope.user = User.get( {username: 'bob'}  );    // GET

        console.log( JSON.stringify(scope.user) )       // {"$promise":{},"$resolved":false} 

So, when I send GET request, it goes OK, building this ur + params:

http://localhost:9000/rest/usersettings/bob

Question, why I have: {"$promise":{},"$resolved":false}

If my GET request leads to json-response back from the server:{"username":"bob","email":"[email protected]"} then I'm expecting to have my scope.user filled by data.

Should I wait somehow promise is ready / resolved ?

Brnaby answered 15/11, 2013 at 18:38 Comment(1)
You can get the data without $promise and $resolved if you modify the Resource and add an interceptor. I've shown that approach here: https://mcmap.net/q/503145/-angular-js-resource-resultInfidelity
S
60

User.get( {username: 'bob'} ) does not return your actual data immediately. It returns something will hold your data when the ajax returns. On that (the $promise), you can register an additional callback to log your data.

You can change your code to:

   scope.user = User.get( {username: 'bob'}  );    // GET
   scope.user.$promise.then(function(data) {
       console.log(data);
   });
Suet answered 15/11, 2013 at 18:47 Comment(5)
If follow this, then I have: 'TypeError: Cannot call method 'then' of undefined' I guess I should inject $promise ..Brnaby
No, $promise is not a service. It should be a property of scope.user. Are you sure you don't have a typo? Cannot reproduce it right now but I see that $promise is defined in your original code ({"$promise":{},"$resolved":false} when stringified)Suet
I suppose you did not switch Angular versions in the meantime. $resource has a breaking change. It's scope.user.$promise.then() for 1.2.x and scope.user.$then() for 1.0.x .Suet
Did not work for me : I still get two objects along with the data. Object { 1421589556: true, $promise: Object, $resolved: true }. I expect only the first entry.Lenrow
@harry, isn't this correct? You could see that resolved:true. It's an array (or array-like obj) with length 1. If you use chrome console, you'll see all its properties. The $promise and $resolved property should be non-enumerable properties, so in your controller if you specify "data in dataset" you're guaranteed those 2 properties won't be enumerated.Dichlamydeous
S
12

You will get your data in there, but not immediately. Read the docs on ngResource:

It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.

Statant answered 15/11, 2013 at 18:42 Comment(3)
I get it. I just got that piece of code from working code. Trying to experiencing with it in local isolated env. So, then it means that even though it is "working" there it might stop working one day.Brnaby
This will never stop working unless you upgrade to some future Angular version which has breaking changes in resource return (very unlikely).Statant
This implies that it never caches anything since it always waits for data to be "returned from the server". If I put this in an expression there will be an infinite digest loop as it constantly goes from not having data to having data...Milksop
B
3

For now I use this (it seems I duplicate this question )

User.get({
    username: 'bob'
}, function(user) {

    user.$update(
        function(data, headers) {
            console.log("GOOD");
        },
        function(err, headers) {
            console.log("BAD");
        }
    );
});
Brnaby answered 15/11, 2013 at 19:2 Comment(0)
B
2

This should work :

User.get( {username: 'bob'} ).$promise.then(function(data) {
    scope.user = data.toJSON();
});

toJSON() cleans up Angular's internal properties ($$).

Bipolar answered 11/1, 2016 at 16:40 Comment(2)
While this may be is a solution, code-only answers are considered to be of low quality. Please add some explanation.Madelenemadelin
Don't know the version of the accepted result, but in angular 1.5 this is the correct answer. The $promise does not belong to the scope.user but to the User.get() function of the factory.Cannikin

© 2022 - 2024 — McMap. All rights reserved.