2

I'm trying to deserialize a paginated end point. The return request for this end point looks like

{
    count: number,
    next: string,
    previous: string,
    data: Array[Objects]
}

The issue I'm having when using js-data to do a findAll, it's injecting this object into the data store. It should be injecting the objects in the data array into the store. So I made a deserialize method on my adapter that looks like this.

deserialize: (resourceConfig:any, response:any) => {
  let data = response.data;
  if (data && 'count' in data && 'next' in data && 'results' in data) {
    data = data.results;
    data._meta = {
      count: response.data.count,
      next: response.data.next,
      previous: response.data.previous
    };
  }
  return data;
}

And this works. The array objects are getting injected into my data store. But the meta information is getting lost.

dataStore.findAll('User').then(r => console.log(r._meta)); // r._meta == undefined

I would like to keep that meta information on the returned object. Any ideas?

user133688
  • 6,864
  • 3
  • 20
  • 36
  • Have you looked at how the pagination is handled in these examples? https://github.com/js-data/js-data-examples https://plnkr.co/edit/ccMe5B – jdobry Aug 15 '16 at 14:37

1 Answers1

2

To do this in v3 you just need to override a couple methods to tweak JSData's handling of the response from your paginated endpoint. The two most important things are to tell JSData which nested property of the response are the records and which nested property should be added to the in-memory store (should be the same nested property in both cases).

Example:

const store = new DataStore({
  addToCache: function (name, data, opts) {
    if (name === 'post' && opts.op === 'afterFindAll') {
      // Make sure the paginated post records get added to the store (and
      // not the whole page object).
      return DataStore.prototype.addToCache.call(this, name, data.results, opts);  
    }
    // Otherwise do default behavior
    return DataStore.prototype.addToCache.call(this, name, data, opts);
  }
});

store.registerAdapter('http', httpAdapter, { 'default': true });

store.defineMapper('post', {
  // GET /posts doesn't return data as JSData expects, so we've got to tell
  // JSData where the records are in the response.
  wrap: function (data, opts) {
    // Override behavior of wrap in this instance
    if (opts.op === 'afterFindAll') {
      // In this example, the Post records are nested under a "results"
      // property of the response data. This is a paginated endpoint, so the
      // response data might also have properties like "page", "count",
      // "hasMore", etc.
      data.results = store.getMapper('post').createRecord(data.results);
      return data
    }
    // Otherwise do default behavior
    return Mapper.prototype.wrap.call(this, data, opts);
  }
});

// Example query, depends on what your backend expects
const query = { status: 'published', page: 1 };
posts.findAll(query)
  .then((response) => {
    console.log(response.results); // [{...}, {...}, ...]
    console.log(response.page); // 1
    console.log(response.count); // 10
    console.log(response.hasMore); // true
  });
jdobry
  • 1,041
  • 6
  • 17