Search code examples
angularjsangular-resource

ngResource transformResponse doesn't seem to be transforming the response


I made a base class, HttpService:

class HttpService
  constructor: (url) ->
    @service = $resource url, {}, @actionOptions()

  actionOptions: ->
    query:
      method: 'GET'
      isArray: true
      transformResponse: (data) =>
        response = []
        wrapped = angular.fromJson(data)
        angular.forEach wrapped[@indexRoot], (item) =>
          response.push @jsonToModel(item)
        response

I inherit like this:

class FooService extends HttpService
  constructor: ->
    super '/api/foos/:id'
    @indexRoot = 'foos'

   all: ->
    @service.query()

  jsonToModel: (data) ->
    new Foo(data)

In general, the idea is to extend HttpService providing the URL of the resource and the index root (JSON has a root element for the index action). I override jsonToModel to provide a way to transform each JSON element in the response into a custom object, in this case Foo.

When debugging, I can see that response is what it should be in actionOptions(), so it seems like transformResponse is returning what I expect, an array of Foos.

Whenever I call FooService.all() though, I get an array of Resources (ngResource default)... anyone have any idea what I'm doing wrong? I've omitted the dependency injection and everything, but it's all working and I have no errors in console.


Solution

  • The $resource service wraps the response in Resource objects using an interceptor, which occurs after the transformResponse, so while transformResponse is a good place to unwrap a root object (the results from there get fed into the interceptors), you will also need an interceptor to call your jsonToModel function.

    The relevant docs:

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

    transformResponse{function(data, headersGetter)|Array.} – transform function or an array of such functions. The transform function takes the http response body and headers and returns its transformed (typically deserialized) version. By default, transformResponse will contain one function that checks if the response looks like a JSON string and deserializes it using angular.fromJson. To prevent this behavior, set transformResponse to an empty array: transformResponse: []

    interceptor - {Object=} - The interceptor object has two optional methods - response and responseError. Both response and responseError interceptors get called with http response object. See $http interceptors.