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":"bob@bobs.com"} then I'm expecting to have my scope.user filled by data.

Should I wait somehow promise is ready / resolved ?

ses
  • 13,174
  • 31
  • 123
  • 226
  • 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: http://stackoverflow.com/a/22807840/592062 – k0nG Apr 02 '14 at 10:00

4 Answers4

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);
   });
Kos Prov
  • 4,207
  • 1
  • 18
  • 14
  • 1
    If follow this, then I have: 'TypeError: Cannot call method 'then' of undefined' I guess I should inject $promise .. – ses Nov 15 '13 at 18:54
  • 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) – Kos Prov Nov 15 '13 at 18:58
  • 8
    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 . – Kos Prov Nov 15 '13 at 19:07
  • 1
    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. – harry Jan 22 '15 at 13:45
  • @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. – nrek Feb 12 '16 at 09:12
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.

Stewie
  • 60,366
  • 20
  • 146
  • 113
  • 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. – ses Nov 15 '13 at 18:46
  • This will **never** stop working unless you upgrade to some future Angular version which has breaking changes in resource return (very unlikely). – Stewie Nov 28 '13 at 08:08
  • 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... – user3338098 Feb 13 '17 at 20:43
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");
        }
    );
});
Community
  • 1
  • 1
ses
  • 13,174
  • 31
  • 123
  • 226
2

This should work :

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

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

devside
  • 2,171
  • 1
  • 19
  • 23
  • While this may be is a solution, code-only answers are considered to be of low quality. Please add some explanation. – Henk van Boeijen Jan 11 '16 at 22:06
  • 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. – Seichi Dec 07 '16 at 22:32