Thoughts on paging in Ember Data Relations


#1

I’ve been thinking about Ember Data, hasMany and async relations. Let’s use the example of a post with comments. That post is wildly popular, and quickly has hundreds or thousands of comments. If I wanted to use the relation to display the comments for the post, I am forced into an all or nothing scenario. As soon as I call post.get('comments') or {{#each comment in comments}}, Ember Data will set off retrieving all of the comments. And to serialize the comment ids for the post, I would, again, need to get all the comment ids to push down to Ember Data.

The benefit of using the relation is that I have the information I need from the post to get the comments. The server knows how they go together (is it a join table? is it a belongs to on the comment?). The way I’ve worked around this in the passed is to have a separate comments component that takes the post and the store, and retrieves a subset of the comments though custom find queries (ie store.find('comment', { post_id: 1, page: 1 })).

It would be nice if there was a way within Ember Data’s relationship modeling to say “Request Page 1” of the comments, and only a subset would be retrieved. I imagine that it would be the adapter’s responsibility to craft the proper request, whether it be taking the first X number of comment ids and GETing those comments, or it could be a request to /posts/1/comments?page=1.

I plan to start an implementation around this, but wanted some feedback to see how others feel about it before I started.


#2

I asked the same question here: http://stackoverflow.com/questions/27429174/filter-paginate-pass-parameters-to-asynchronous-ember-data-relationship-requests


#3

Perhaps use some form of arrangedContent like here:

import Ember from "ember";
import pagedArray from 'ember-cli-pagination/computed/paged-array';

export default Ember.ArrayController.extend({
  sortProperties: ['date'],
  sortAscending: false,
  
  page: 1,
  perPage: 5,

  pagedContent: pagedArray("arrangedContent", {pageBinding: "page", perPageBinding: "perPage"}),

  queryParams: ["page", "perPage"],

  totalPagesBinding: "pagedContent.totalPages"
});

Working example that uses this code: http://exmer.com/bloggrcouch


#4

I think this would be very useful if it there was direct support for this in ember data.

Also would be helpful to document the front end and backend implementation to make this work with a simple guide.

I also wonder if there are other ways to conceptualize this than pages? What about ranges or requesting multiple subsets at once?

  • firstComment
  • lastComment
  • mostRecentComments
  • commentRange: [111-222]
  • etc

The general problem of fetching subsets of database from a very large set of possible data has always been a little confusing so this is very helpful.


#5

As others have mentioned, I think skip + limit is better than pagination (in most cases) for the following two reasons:

  1. No need for a server-side count (may or may not be relevant performance-wise) and
  2. it lends itself well to the ‘load more’ and ‘infinite scroll’ patterns.

I have some code wiring this up, through route + controller and skip plus limit on the server-side. However, it’s not super-well packaged, but if someone is interested I could (at least) send over a ‘dump’ of the code we’re currently using.

I would want to package it as an ember-addon too, but don’t have much time right now.


#6

I realize this post is a bit old, but does anyone have a good solution for this?

I have a project that has many relations that require query parameters to be passed. For instance, in my api a User has many Projects, and a Project has many Orders. It seems like there should be an easy way to tell ember -data to:

Get page 2 of User #1’s Projects (/users/1/projects?page=2)

or Only completed orders in Project #5 (/projects/5/orders?filter=completed)

Am I missing something?


#7

@ianmcdaniel I do filter and paginate like this:

It is not exactly what you want but perhaps it helps you to create a filter on completed.


#9

I meant in the context of ember-data. I need to specifically make a call to the server to request a has many relation with some query params. ( i.e. /users/1/projects?someparam=whatever ).


#10

change findAll(type) to query(type, {query}) ? It is in ember-data 1.13 but I have not used it yet.


#11

but that only works on the model, not the has many relationship.

this.store.find('user',1).then(function(user){
  // this makes a request to 'user/1/projects' but how do I pass query parameters here?
  user.get('project');
})