Skip to content

Commit

Permalink
Merge pull request #18 from truenorth/customize-pagination-params
Browse files Browse the repository at this point in the history
Allow customization of pagination API
  • Loading branch information
hhff committed May 21, 2015
2 parents f1af7f2 + 7f10048 commit 848faaf
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ env:

matrix:
fast_finish: true
allow_failures:
- env: EMBER_TRY_SCENARIO=ember-canary

before_install:
- export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH
Expand Down
63 changes: 56 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,67 @@ Now, whenever the `infinity-loader` is in view, it will send an action to the ro

When the new records are loaded, they will automatically be pushed into the Model array.

#### JSON Response
## Advanced Usage

### JSON Request/Response Customization

By default, ember-infinity will send pagination parameters as part of a GET request as follows

````
/items?per_page=5&page=1
````

The response provided by your server should include the number of total pages.
and will expect to recieve metadata in the response payload via a `total_pages` param in a `meta` object

```json
{ "meta": { "total_pages": 4 } }
```js
{
items: [
{id: 1, name: 'Test'},
{id: 2, name: 'Test 2'}
],
meta: {
total_pages: 3
}
}
```

If your query returns 20 objects, and you're showing 6 per page, then the
number of total pages would be 4.
If you wish to customize some aspects of the JSON contract for pagination, you may do so via your routes. For example:

## Advanced Usage
```js
import Ember from 'ember';
import InfinityRoute from "ember-infinity/mixins/route";

export default Ember.Route.extend(InfinityRoute, {

perPageParam: "per", // instead of "per_page"
pageParam: "pg", // instead of "page"
totalPagesParam: "meta.total", // instead of "meta.total_pages"

model() {
/* Load pages of the Product Model, starting from page 1, in groups of 12. */
return this.infinityModel("product", { perPage: 12, startingPage: 1 });
}
});
```

This will result in request query params being sent out as follows

````
/items?per=5&pg=1
````

and ember-infinity will be set up to parse the total number of pages from a JSON response like this:

```js
{
items: [
...
],
meta: {
total: 3
}
}
```

### infinityModel

Expand Down
36 changes: 32 additions & 4 deletions addon/mixins/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,30 @@ export default Ember.Mixin.create({
*/
_modelPath: 'controller.model',

/**
* Name of the "per page" param in the
* resource request payload
* @type {String}
* @default "per_page"
*/
perPageParam: 'per_page',

/**
* Name of the "page" param in the
* resource request payload
* @type {String}
* @default "page"
*/
pageParam: 'page',

/**
* Path of the "total pages" param in
* the HTTP response
* @type {String}
* @default "meta.total_pages"
*/
totalPagesParam: 'meta.total_pages',

/**
@private
@property _canLoadMore
Expand Down Expand Up @@ -113,18 +137,22 @@ export default Ember.Mixin.create({
this.set('_modelPath', modelPath);
this.set('_extraParams', options);

var params = Ember.merge({ page: startingPage, per_page: perPage }, options);
var requestPayloadBase = {};
requestPayloadBase[this.get('perPageParam')] = perPage;
requestPayloadBase[this.get('pageParam')] = startingPage;

var params = Ember.merge(requestPayloadBase, options);
var promise = this.store.find(modelName, params);

promise.then(
function(infinityModel) {
var totalPages = infinityModel.get('meta.total_pages');
infinityModel => {
var totalPages = infinityModel.get(this.get('totalPagesParam'));
_this.set('_currentPage', startingPage);
_this.set('_totalPages', totalPages);
infinityModel.set('reachedInfinity', !_this.get('_canLoadMore'));
Ember.run.scheduleOnce('afterRender', _this, 'infinityModelUpdated', { lastPageLoaded: startingPage, totalPages: totalPages, newObjects: infinityModel });
},
function() {
() => {
throw new Ember.Error("Could not fetch Infinity Model. Please check your serverside configuration.");
}
);
Expand Down
65 changes: 65 additions & 0 deletions tests/unit/mixins/route-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,71 @@ test('it sets state before it reaches the end', function(assert) {
assert.ok(!model.get('reachedInfinity'), 'Should not reach infinity');
});

test('it allows customizations of request params', assert => {
var RouteObject = Ember.Route.extend(RouteMixin, {
perPageParam: 'per',
pageParam: 'p',
model() {
return this.infinityModel('item');
}
});
var route = RouteObject.create();

var dummyStore = {
find(modelType, findQuery) {
assert.deepEqual(findQuery, {per: 25, p: 1});
return new Ember.RSVP.Promise(resolve => {
Ember.run(this, resolve, Ember.Object.create({
items: []
}));
});
}
};

route.store = dummyStore;

var model;
Ember.run(function() {
route.model().then(function(result) {
model = result;
});
});
});

test('it allows customizations of meta parsing params', assert => {
var RouteObject = Ember.Route.extend(RouteMixin, {
totalPagesParam: 'pagination.total',
model() {
return this.infinityModel('item');
}
});
var route = RouteObject.create();

var dummyStore = {
find(modelType, findQuery) {
return new Ember.RSVP.Promise(resolve => {
Ember.run(this, resolve, Ember.Object.create({
items: [{id: 1, name: 'Walter White'}],
pagination: {
total: 22
}
}));
});
}
};

route.store = dummyStore;

var model;
Ember.run(function() {
route.model().then(function(result) {
model = result;
});
});

assert.equal(22, route.get('_totalPages'));
});

test('it sets state when it reaches the end', function(assert) {

var RouteObject = Ember.Route.extend(RouteMixin, {
Expand Down

0 comments on commit 848faaf

Please sign in to comment.