AngularJS’s built-in ngResource is a great tool for natively supporting REST APIs in your Angular application. But what happens when you need to support something besides a simple call that retrieves a list of JSON objects? You quickly run into the limits of ngResource.
Here’s a great case where you might need to do something more complex: paging. Say you want to get a list of objects, and there’s 10,000 or so of them. You don’t want to send 10,000 objects to your frontend app. You want to send a portion of them, but you still need to indicate to the app that there are more.
Surprisingly, considering how widespread this pattern is in web development, there does not seem to be a native way to accomplish this. But you can extend ngResource. Here’s how I did it.
From The Backend
There is some debate on what the proper way to handle paging is for RESTful endpoints. Some people say you should send it as a header. Other say you should send it as part of the data return. I chose the latter. Here’s an example of a return I might implement:
As you can see here, the data is returned in a wrapper structure that indicates how many matches were found and and how many are returned and that we’re only returning a subset. So the frontend knows that it can page the results.
Intercepting The Response
The next thing I did was implement an
$httpProvider transformer to transform the response.
What this does is pull out the values and add them (temporarily) to the data array before passing that on ngResource. The try/catch block is to check to be sure we actually got a valid JSON response and not, say, a template or something. And if it’s not a JSON structure in a format we recognize (like an endpoint that hasn’t been converted to the new structure) it just passes the full data along.
The nice thing about doing this with an transformer at the
$http level is that this logic now lives here instead of in your models.
So now you have the
$returned being passed along to ngResource, but ngResource is still discarding it. Here’s where the magic happens. We create a wrapper provider around ngResource that can pull these variables out and make them available.
Basically what this does is extend
$resource to add a interceptor for each action that pulls the variables from the data collection and puts them on the resource itself.
With this, you now have
$returned as properties on the resource collection returned. Instead of calling
$resource(...) in your factories, you now call
$ourResource(...) instead. It’s a 1:1 replacement since
$ourResource wraps and extends
Now, with that done, you can do something like this in your views:
Theoretically you could even implement the entire thing in your
$ourResource wrapper by implementing
transformResponse in the inner
angular.forEach loop. That might even be a better idea, but I like this approach.
Thanks goes to this JSFiddle that put me on the right path to solving this.