3

Given angular.js service:

angular.module('mymodule').factory('Products', ['$resource',
    function($resource) {
        return $resource('/path/to/getProducts', {}, {
            find: {
                method: 'GET',
                isArray: false
            }
        });
    }
]);

In the controller of mymodule I make find query:

$scope.findAll = function () {
    Products.find(function (products) {
        console.log(Object.keys(products));
        // ['prodA', 'prodB', ... , '$promise', '$resolved']
        for (var i in products) {
            if (!products.hasOwnProperty(i)) continue;
            console.log(products[i].description.someprop);
            // Got error: Cannot read property 'someprop' of undefined
            // Trust me: I debug this place. someprop is defined for all items except that two
        }
    });
};

It works fine but returns $promise and $resolved with data set, so that I can not loop through my data.

Angular documentations says that the Resource instances and collection has these additional properties. But I don't understand exactly how to control it in my code.

What am I doing wrong? How to prevent it?

Boris Zagoruiko
  • 12,705
  • 15
  • 47
  • 79

4 Answers4

8

Indeed it's a bit more complicated when you're not working with arrays.

The response object sent back from the server contains:

  • the resource object (your data + $promise and $resolved, that's what you get in your callback)
  • a config object (the headers, the method used, the url called, etc) and a headers function
  • and a data object, that's what we want ! It contains just the data.

But you will only get to see response.resource in your then(). You therefore need to intercept the response sent by the server to get the data instead:

return $resource('/path/to/getProducts', {}, {
        find: {
           method: 'GET',
           isArray: false,
           interceptor: {
             response: function(response) {  
               return response.data;
             }
           }
        }
    });

And then in your controller :

Products.find().$promise.then(
    function(products){
        angular.forEach(products, function(value, index){
            console.log(value);
        });
    }
);

Tell me if this works for you.

Plunker Demo

deonclem
  • 860
  • 10
  • 25
  • stackoverflow doesn't allow me to award your answer with bounty right now but I'll do it in 20 hours ) – Boris Zagoruiko Oct 02 '14 at 16:58
  • @deonclem is there any way of setting this response interceptor as the default behavior for all $resource's? Repeating this code on all of them don't seems correct. – Guilherme Miranda Oct 20 '14 at 15:07
  • Check the doc : https://docs.angularjs.org/api/ng/service/$http under the section "Interceptors". This will intercept every `$http` calls you make (as `$resource` uses `$http`). If you want to only intercept specific calls, you can try : http://stackoverflow.com/questions/23021416/how-to-use-angularjs-interceptor-to-only-intercept-specific-http-requests – deonclem Oct 21 '14 at 09:03
0

Resources return a promise, you can retrieve the data from the promise using then().

Products.find().$promise.then(function (products) {
    console.log(Object.keys(products));
});
Ben Fortune
  • 31,623
  • 10
  • 79
  • 80
  • They will be, since it returns a promise... You can still loop over your collection. Read up on [promises](https://docs.angularjs.org/api/ng/service/$q). – Ben Fortune Sep 30 '14 at 13:30
  • I got errors. Does It matter if I loop with simple for loop, not with ng-repeat? Updated my question with code – Boris Zagoruiko Sep 30 '14 at 13:36
0

I guess your problem is 'isArray: false'. So your products is not an array, but object. Set 'isArray: true' and you can iterate for(var product in products) all day.

Petr Averyanov
  • 9,327
  • 3
  • 20
  • 38
  • My products is not array but object so I set isArray to false. If isArray is set to true but backend returns object angular throws errow Error: [$resource:badcfg] so I can not do this – Boris Zagoruiko Sep 30 '14 at 14:26
0

Try doing response.toJSON and it returns just your json excluding promise and resolve.

data.$promise.then(function(myResponse) {
    var actualData = myResponse.toJSON();
}
bcsshdha
  • 129
  • 2
  • 8