Using $resource.query, I want to return an object that contains an array of the actual resource
Asked Answered
C

4

11

By default, the $resource.query() is set up to expect an array of objects that become $resource objects. To accommodate paging in a nice, restful way, I have my GET /api/widgets endpoint set up to return the following object:

{
  currentPage: 1,
  perPage: 20,
  totalItems: 10039,
  items: [{...}, {...}, {...}]
}

Is there a way to make it so that angular will know that the items property is the array of items to be $resource objects?

Cyprian answered 26/1, 2015 at 18:13 Comment(0)
D
23

You need to specify your own custom action.

I imagine your code looks something like this:

factory('Widget', function($resource) {
  return $resource('/api/widgets');
});

Change it to this:

factory('Widget', function($resource) {
  return $resource(/api/widgets, null, {
    query: {
      method: 'GET',
      isArray: true,
      transformResponse: function(data) {
        return angular.fromJson(data).items;
      }
    }
  });
});
Deodar answered 26/1, 2015 at 18:26 Comment(3)
So, with this approach, how do I get access to the paging information from outside the transformResponse method? You've definitely already answered the original question, but now I have a new problem :)Cyprian
Not entirely sure, but you could try this var widgets = Widget.query(); widgets.$promise.then(function(data) {console.log(data);});.Deodar
So what I did, was set isArray: false and keep the shape of the returned object. I iterated through item in items and just replaced them: data.items[i] = new Widget(item); It works great! I really appreciate your help with this.Cyprian
A
2

the easy was is to use $resouce.get, if you wan to use query you can override that behaivor.

$resource('/notes/:id', null,
{
    'query':  {method:'GET', isArray:false}
});

more info https://docs.angularjs.org/api/ngResource/service/$resource

Ayn answered 26/1, 2015 at 18:20 Comment(3)
This doesn't solve my problem. The entire response object will be a $resource, and attempting to call $save or $update will attempt to persist values that aren't part of the the actual resource's model. I need to configure $resource.query() to know that the actual resource objects are contained in the items array of the response.Cyprian
I have done this, and works for me, I dont see how it wont work, when you call the update you will speciy the id and the new object, i dont see how it wont work myresource.update({id:1}. { propery1: 1, property2: 2 })Ayn
This will work if I'm using $resource strictly as a mechanism for constructing requests and getting a response object, however, there are additional features of $resource that aren't widely understood. Specifically, the object(s) returned by a REST endpoints become $resource objects themselves. In my case, I needed a way to tell angular that the list property of the returned object are the actual resources. See the accepted answer.Cyprian
T
0

I just had the same problem, and I wanted to propose a solution which could be a little better:

factory('Widget', function($resource) {
    return $resource(/api/widgets, null, {
        query: {
            interceptor: {
                response: function(response) {
                    return response.data.items;
                }
            }
        }
    }
}

I think it may be better, because you are reusing the standard angular behaviour (which is, actually, doing a little more than fromJson) and intercepting the output result to filter what you want.

Trichromat answered 26/3, 2016 at 14:42 Comment(0)
A
0

I use this pattern for query with paging informations.

module.config(function($resourceProvider){
    $resourceProvider.defaults.actions.query = {
        method: 'GET',
        interceptor: {
            response: function(response) {
                response.resource.$totalCount = response.data.totalCount;
                response.resource.$limit = response.data.limit;
                response.resource.$offset = response.data.offset;
                return response.resource;
            }
        },
        transformResponse: function(data, headers, status) {
            var out = angular.fromJson(data);
            out.data.totalCount = out.totalCount;
            out.data.limit = out.limit;
            out.data.offset = out.offset;
            return out.data;
        },
        isArray: true
    };
})
Angeloangelology answered 20/7, 2017 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.