18

I'm using an API that returns JSON data in this format:

{
    paging: {
        previous: null,
        next: null
},
    data: [
        { title: 'First Item' },
        { title: 'Second Item' },
        ...
    ]
}

I'm using Angular's $resource service to fetch this data.
My code - which is located in a controller - goes something like this:

var Entity = $resource('/api/entities');
var entities = $scope.entities = Entity.get();

And then, in the view, I can display the data like this:

<ul>
  <li ng-repeat="entity in entities.data">{{entity.title}}</<li>
</ul>

It all works fine, but:

  • I'd rather expose only the contents of entities.data to the view, instead of the whole entities object. How can I intercept the data returned by the GET request to modify it before it populates $scope.entities?
  • Correlated question: since I am fetching an array of data, it would be cleaner to use Entity.query() instead of Entity.get(). But if I use Entity.query() in the code above, I get an error "TypeError: Object # has no method 'push'". This makes sense, since the API is returning an object instead of an array (hence, no 'push' method on the object). Again, if I could extract the .data attribute from the response, I'd have an array.

Following these indications by Dan Boyon, I managed to customize the default $resource service and to override the .get() or .query() methods, but I'm not sure where to go from there.

3
  • out of curiosity (even though this is old), why didn't your API return the paging data in the headers? Commented Dec 8, 2014 at 22:30
  • @EddieMongeJr: No idea, Eddie. I can't even remember which API it was but the thing is I had no control over it. Commented Dec 9, 2014 at 8:13
  • Take a look at the 'transformResponse' option in docs.angularjs.org/api/ngResource/service/$resource Commented Apr 13, 2016 at 11:36

2 Answers 2

24

I don't think you need to modify the get or query defaults. Just use the success callback to do what you want. It should be more robust as well.

Entity.get(
    {}, //params
    function (data) {   //success
        $scope.entities = data.data;
    },
    function (data) {   //failure
        //error handling goes here
    });

Html will be cleaner, too:

 <ul>
      <li ng-repeat="entity in entities">{{entity.title}}</<li>
 </ul>

By the way, I usually declare services for my resources and then inject them into my controllers as I need them.

 myServices.factory('Entity', ['$resource', function ($resource) {
     return $resource('/api/entities', {}, {
     });
 }]);
Sign up to request clarification or add additional context in comments.

6 Comments

Hey Chris! Thanks, that works perfectly. I was aware of the success and failure callbacks, but it didn't occur to me to do the scope assignment there.
Trying this same method, I'm getting an error saying "TypeError: Object #<Resource> has no method 'push'". The documentation for $resource is really bad. Their examples look totally different from yours and neither is working.
@blesh that error usually occurs when you're receiving back an array into $resource when isArray: false, such as using get. If you're receiving an array you probably want to use query which defaults isArray: true.
That was exactly the problem. Now however, the array of strings I'm getting back from my service actually comes back as an array of arrays. So rather than it being: ["one", "two"] it's [['o','n','e'],['t','w','o']] ... very strange.
... apparently my issue mentioned in the above comment has to do with me returning an array of strings and not objects. Which makes sense given how $resource adds methods to the results it gets. groups.google.com/forum/#!msg/angular/QjhN9-UeBVM/…
|
1

You can use the Response Transformer (transformResponse) like this:

$resource('/api/entities', {}, {
        query: {
            method: 'GET',
            responseType: 'json',
            isArray: true,
            transformResponse: function (response) {
                return response.data;
            }
        }
    });

This code modifies the "query" method behaviour, you can do the same for "get" ... !

1 Comment

Fantastic! Mind the "responseType" mentioned above - otherwise you'll get a String.

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.