Git Product home page Git Product logo

ember-cli-pagination's Introduction

Ember CLI Pagination

Build Status

Simple pagination addon for your Ember CLI app.

โš ๏ธ This addon works with Ember version 3.12.x and below and from Ember version 3.16.2 up to 3.28. From ember 4.x and on remote pagination is not working yet as mixins and array observers are fully deprecated (needs to be rethought). Some examples are still in non Octane style.

Todos

Features:

  • Supports multiple types of pagination:
    • Local
    • Remote
    • Infinite
  • Default pagination template - but you can write your own
  • Current page bound to the page query param
  • Compatible with the Kaminari API Rails gem

Questions?

This is a new project, but many people are already using it successfully. If you have any trouble, open an issue, and you should get help quickly.

Requirements

  • ember-cli 1.13.0 or higher (For earlier versions use ember-cli-pagination 0.6.6)
  • ember-cli-pagination 0.9.0 or higher for current docs.

Installation

ember install ember-cli-pagination

For ember-cli < 1.13.0:

npm install [email protected] --save-dev

Usage

Scenarios

Primitives

Other

Scenarios

Local Store

This scenario applies if:

  • Have all of your records already loaded client-side.
  • Wish to display one page of records at a time.
  • Want to have a page query parameter (optional).
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { alias, oneWay } from '@ember/object/computed';
import pagedArray from 'ember-cli-pagination/computed/paged-array';

export default class PostsController extends Controller {
  // setup our query params
  queryParams: ['page', 'perPage'];

  // set default values, can cause problems if left out
  // if value matches default, it won't display in the URL
  @tracked page = 1;
  @tracked perPage = 10;

  // can be called anything, I've called it pagedContent
  // remember to iterate over pagedContent in your template
  @pagedArray('model', {
    page: alias('parent.page'),
    perPage: alias('parent.perPage'),
  })
  pagedContent;

  // binding the property on the paged array
  // to a property on the controller
  @oneWay('pagedContent.totalPages') totalPages;
}
{{#each pagedContent as |post|}}
  {{! your app's display logic}}
{{/each}}

<PageNumbers @content={{pagedContent}} />

If you don't want to have query params, you may leave them out, along with the 3 bindings. The rest will still work.

In older versions of Ember you would have done:

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

export default Ember.Controller.extend({
  // setup our query params
  queryParams: ['page', 'perPage'],

  // set default values, can cause problems if left out
  // if value matches default, it won't display in the URL
  page: 1,
  perPage: 10,

  // can be called anything, I've called it pagedContent
  // remember to iterate over pagedContent in your template
  pagedContent: pagedArray('content', {
    page: Ember.computed.alias('parent.page'),
    perPage: Ember.computed.alias('parent.perPage'),
  }),

  // binding the property on the paged array
  // to a property on the controller
  totalPages: Ember.computed.oneWay('pagedContent.totalPages'),
});
{{#each pagedContent as |post|}}
  {{! your app's display logic}}
{{/each}}

{{page-numbers content=pagedContent}}

Or in even older Ember versions:

{
  // ...

  // can be called anything, I've called it pagedContent
  // remember to iterate over pagedContent in your template
  pagedContent: pagedArray('content', {
    pageBinding: "page",
    perPageBinding: "perPage"
  }),

  // binding the property on the paged array
  // to a property on the controller
  totalPagesBinding: "totalPages"
}

Notes

  • There is no need to touch the route in this scenario.
  • There used to be route and controller mixins, and they may return in the future. For now, they were too much overhead, and they were too much magic. If you think getting rid of the mixins is a mistake, please open an issue and let me know.

Remote Paginated API

This scenario applies if:

  • Loading your records from a remote pagination-enabled API.
  • Wish to display one page of records at a time.
  • Want to have a page query parameter. (optional)
  • Need to access a zero Based Index remote pagination-enabled API. (optional)

1:1 based page index

import Route from '@ember/routing/route';
import { tracked } from '@glimmer/tracking';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';

export default class PostsRoute extends Route.extend(RouteMixin) {
  // optional. default is 10
  perPage: 25;

  model(params) {
    // todo is your model name
    // returns a PagedRemoteArray
    return this.findPaged('post', params);
  }
}

Zero based page index

import Route from '@ember/routing/route';
import { tracked } from '@glimmer/tracking';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';

export default class PostsRoute extends Route.extend(RouteMixin) {
  // optional. default is 10
  perPage: 25;

  model(params) {
    // todo is your model name
    // returns a PagedRemoteArray
    return this.findPaged('post', params, { zeroBasedIndex: true });
  }
}
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { alias } from '@ember/object/computed';

export default class PostsController extends Controller {
  // setup our query params
  queryParams: ['page', 'perPage'];

  // binding the property on the paged array
  // to the query params on the controller
  @tracked page = alias('model.page');
  @tracked perPage = alias('model.perPage');
  @tracked totalPages = alias('model.totalPages');
}
{{#each model}}
  {{! your app's display logic}}
{{/each}}

<PageNumbers @content={{pagedContent}} />

If you don't want to have query params, you may leave them out, along with the 3 bindings. The rest will still work.

In older versions of Ember you would have done:

{
  // ...

  // binding the property on the paged array
  // to the query params on the controller
  pageBinding: "content.page",
  perPageBinding: "content.perPage",
  totalPagesBinding: "content.totalPages",
}

Passing other params to findPaged

If your params object has other params, they will be passed to your backend.

export default class PostsRoute extends Route.extend(RouteMixin) {
  model(params) {
    // params is {page: 1, name: "Adam"}

    return this.findPaged('post', params);

    // server will receive params page=1, name=Adam
  }
}

Using other names for page/perPage/total_pages

You may pass an optional paramMapping arg. This is a hash that allows you to change the param names for page/perPage/total_pages.

Note that the default param name for perPage is per_page.

page and perPage control what is sent to the backend. total_pages controls where we expect to find the total pages value in the response from the backend.

import Route from '@ember/routing/route';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';

export default class PostsRoute extends Route.extend(RouteMixin) {
  model(params) {
    params.paramMapping = {
      page: 'pageNum',
      perPage: 'limit',
      total_pages: 'num_pages',
    };
    return this.findPaged('post', params);
  }
}

You can also pass a mapping function for the paramMapping. A common usage for this would be a limit and offset API backend. This is done by passing an array as the mapping. The first item in the array being the param name, and the second item being the value mapping function. The function should accept one parameter, an object with keys page and perPage and their respective values.

import Route from '@ember/routing/route';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';

export default class PostsRoute extends Route.extend(RouteMixin) {
  model(params) {
    params.paramMapping = {
      page: [
        'offset',
        function (obj) {
          return (obj.page - 1) * obj.perPage;
        },
      ],
      perPage: 'limit',
    };
    return this.findPaged('todo', params);
  }
}

Get updates outside

Sometimes you may need to handle remote paginated API without refreshModel param, to provide more smooth update of data. In that case you could use default method to track it or add a custom observer.

Here is an example how to use the default one:

// routes/index.js
export default Ember.Route.extend({
  queryParams: {
    page: {},
    perPage: {}
  },
  model() {
    return Ember.RSVP.hash({
      approveVideos: this.findPaged('approve-video', queryParams),
      approveVideoActions: this.findPaged('approve-video-action', queryParams)
    });
  }
});

//controllers/index.js
export default Ember.Controller.extend({
  filteredStuff: Ember.computed('model.approveVideos.contentUpdated', function () {
    return this.get('model.approveVideos').map(...);
  })
});

As far as returned from '.findPaged()' method instance of PagedRemoteArray inherits Ember.Evented, you can subscribe on contentWillChange and contentUpdated events.

Notes

  • There used to be a controller mixin, and they may return in the future. For now, it was too much overhead, and it was too much magic. If you think getting rid of the mixin is a mistake, please open an issue and let me know.
  • Related: Setup a Paginated Rails API

Force reloading data

This scenario assumes that we know we need to refresh the data from server. For example when we sent new data to the server and we want to display them in our application:

// route.js
export default Route.extend(RouteMixin, {
  model() {
      return this.findPaged('post'),
  }
});
{{! template.hbs }}

<button {{action 'createNewPost'}}>Click me to create new post</button>

<ul>
  {{#each model as |post|}}
    <li>{{post.id}}</li>
  {{/each}}
</ul>
// controller.js
export default Controller.extend({
  actions: {
    createNewPost() {
      // Note that this by itself won't make the post appear in paginated list of posts
      let newPost = this.store.createRecord('post');

      // Not even saving the data server side will make it appear on user's screen
      return newPost.save().then(() => {
        // This will force the ember-cli-pagination to re-fetch current page
        this.get('model').setOtherParam(
          'nameOrValueOfThisPropertyDoesNotReallyMatter',
          true
        );
      });
    },
  },
});

Remote Unpaginated API

This scenario applies if:

  • Loading your records from a remote API that is not pagination-enabled.
  • You are ok with loading all records from the API in order to display one page at a time.
  • Wish to display one page of records at a time.
  • Want to have a page query parameter (optional).

This scenario is identical to the Local Store scenario.


Paginating a Filtered List

This scenario applies if:

  • Have all of your records already loaded client-side.
  • You are filtering those records down to create a subset for display
  • Wish to display one page of records at a time.
  • Want to have a page query parameter (optional).
import Ember from 'ember';
import pagedArray from 'ember-cli-pagination/computed/paged-array';

export default Ember.Controller.extend({
  // setup our query params
  queryParams: ['page', 'perPage'],

  // set default values, can cause problems if left out
  // if value matches default, it won't display in the URL
  page: 1,
  perPage: 10,

  // only want records that are not completed
  filteredContent: Ember.computed.filterBy('content', 'isCompleted', false),

  // can be called anything, I've called it pagedContent
  // remember to iterate over pagedContent in your template
  pagedContent: pagedArray('filteredContent'),

  // binding the property on the paged array
  // to the query params on the controller
  page: Ember.computed.alias('pagedContent.page'),
  perPage: Ember.computed.alias('pagedContent.perPage'),
  totalPages: Ember.computed.oneWay('pagedContent.totalPages'),
});
{{#each pagedContent}}
  {{! your app's display logic}}
{{/each}}

{{page-numbers content=pagedContent}}

If you don't want to have query params, you may leave them out, along with the 3 bindings. The rest will still work.

In older versions of Ember you would have done:

{
  // ...

  // binding the property on the paged array
  // to the query params on the controller
  pageBinding: "pagedContent.page",
  perPageBinding: "pagedContent.perPage",
  totalPagesBinding: "pagedContent.totalPages"
}

Notes

  • There is no need to touch the route in this scenario.

Infinite Pagination with All Records Present Locally

The infinite pagination sections of the docs is not yet up to my preferred quality level. If you have any questions or problems, please do not hesitate to make an issue.

The example below does not use a page query param, although that is certainly possible.

Controller:

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

export default Ember.Controller.extend({
  pagedContent: pagedArray('content', { infinite: 'unpaged', perPage: 10 }),

  actions: {
    loadNext: function () {
      this.get('pagedContent').loadNextPage();
    },
  },
});

"unpaged" in this example indicates the source array (the content property) is a regular (unpaged) array, as opposed to a PagedArray.


Infinite Pagination with a Remote Paginated API

The example below does not use a page query param, although that is certainly possible.

// controller

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

export default Ember.Controller.extend({
  pagedContent: pagedArray('content', { infinite: true }),

  actions: {
    loadNext: function () {
      this.get('pagedContent').loadNextPage();
    },
  },
});

{infinite: true} in this example indicates the source array (the content property) is a paged array, in this case a PagedRemoteArray.

// route

import Ember from 'ember';
import RouteMixin from 'ember-cli-pagination/remote/route-mixin';

export default Ember.Route.extend(RouteMixin, {
  model: function (params) {
    return this.findPaged('todo', params);
  },
});

Primitives

page-numbers Component

Displays pagination controls.

Todos

Features:

  • A clickable link for each page.
  • Previous and next buttons, disabled when appropriate.
  • The link to the current page receives the .active class.
  • Styling with bootstrap, if included.

Including in your template

There are two ways to use this component.

Backed by a PagedArray

This is the easier and most common way.

Ember.Controller.extend({
  pagedContent: pagedArray('content'),
});
{{#each pagedContent}}
  {{! your app's display logic}}
{{/each}}

{{page-numbers content=pagedContent}}

Clicking a page number will:

  • Display the rows on the clicked page.
  • Update pagedContent.page to the clicked page.

See the pagedArray doc for more information on the pagedArray helper.

Bind currentPage and totalPages to your properties directly

Ember.Object.extend({
  page: 1,
  totalPages: 10,
});
{{page-numbers currentPage=page totalPages=totalPages}}

Clicking a page number will:

  • Update the page property to the clicked page.

Customization

You can use your own template for the pagination controls. Create it in your app at app/templates/components/page-numbers.hbs and it will be used automatically. Note: do not use ember generate component page-numbers, as this will also create an empty JavaScript controller file. Create/copy the page-numbers.hbs file yourself.

See the default template for an example.

To always show the first and last pages (in addition to the pages that would be shown normally), set the showFL property

{{page-numbers content=content showFL=true}}

Future Additions

  • <</>> links to move more than one page at a time.
  • Configuration settings to change behavior, remove arrows, etc.

pagedArray Computed Helper

Creates a computed property representing a PagedArray.

A PagedArray acts just like a normal array containing only the records on the current page.

Takes two arguments:

  • A contentProperty argument, representing the name of the "all objects" property on the source object.
  • An optional options hash. Currently the only allowed options are page and perPage, both integers

A PagedArray has several properties you may find useful:

  • page: the current page (Default: 1)
  • perPage: how many records to have on each page (Default: 10)
  • totalPages: the total number of pages
import pagedArray from 'ember-cli-pagination/computed/paged-array';

export default Ember.Object.extend({
  // The property that contains all objects
  // In a real app, often set by the route
  content: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],

  // the PagedArray
  pagedContent: pagedArray('content', { perPage: 5 }),
});

In this example, these properties will be available:

  • pagedContent.page
  • pagedContent.perPage
  • pagedContent.totalPages

The pagedContent property can serve as a backing array for pagination controls. See the page-numbers component for details.


PagedLocalArray

PagedLocalArray represents a page of records from the list of all records.

All records must be loaded client-side in order to use PagedArray.

It takes three arguments at creation, in a standard options hash passed to PagedArray#create:

  • content - list of all records
  • page - Optional (Default 1)
  • perPage - Optional (Default 10)

Once the data is loaded, you may iterate over a PagedArray as you would a normal array.

The object acts as a promise, with a working then method.

import PagedArray from 'ember-cli-pagination/local/paged-array';

var all = Ember.A([1, 2, 3, 4, 5]);
var paged = PagedArray.create({ content: all, perPage: 2 });

equal(paged.get('length'), 2);
deepEqual(paged.toArray(), [1, 2]);

paged.set('page', 3);
deepEqual(paged.toArray(), [5]);

all.pushObject(6);
deepEqual(paged.toArray(), [5, 6]);

Updating

A Paged will be updated when the page property is changed.

Binding

You may bind PagedArray#page like any property.

To update records when a page property changes:

Ember.Controller.extend({
  // the content property represents a paged array
  page: Ember.computed.alias('content.page'),
});

In older versions of Ember you would have done:

Ember.Controller.extend({
  // the content property represents a paged array
  pageBinding: 'content.page',
});

PagedRemoteArray

PagedRemoteArray represents a page of records fetched from a remote pagination-enabled API.

It takes six arguments at creation, in a standard options hash passed to PagedRemoteArray#create:

  • modelName - singular
  • store
  • page
  • perPage
  • otherParams - optional. If provided, will be passed on to server at same level as page and perPage
  • paramMapping - optional. Allows configuration of param names for page/perPage/total_pages

Once the data is loaded, you may iterate over a PagedRemoteArray as you would a normal array.

The object acts as a promise, with a working then method. If you are manually iterating over records outside of the standard workflow, make sure to use then with standard promise semantics, just as you would an object returned from a normal store.find call.

import PagedRemoteArray from 'ember-cli-pagination/remote/paged-remote-array';

export default Ember.Route.extend({
  model: function (params) {
    // possible params are params.page and params.per_page
    // Ember's query param logic converts perPage to per_page at some point, for now just dealing with it.

    return PagedRemoteArray.create({
      modelName: 'post',
      store: this.store,
      page: params.page || 1,
      perPage: params.per_page || 10,
    });
  },
});

Updating

A PagedRecordArray will make a new remote call to update records when the page property is changed. Again, standard promise usage applies here.

// pagedArray represents a PagedRemoteArray, already created and loaded with data, with page=1
// var pagedArray = ....

// this will trigger the remote call for new data
pagedArray.set('page', 2);

pagedArray.then(function () {
  // the data is loaded.
  pagedArray.forEach(function (obj) {
    // your logic
  });
});

Reloading

A PagedRecordArray has a reload method which you can use to refresh the current data. All params passed when constructing the PagedRecordArray will remain unchanged. The method returns a promise which is resolved when new data are loaded.

// pagedArray represents a PagedRemoteArray, already created
// var pagedArray = ....

// this will trigger the remote call to refresh the current page
pagedArray.reload().then(() => {
  // data loaded
});

Binding

You may bind PagedRemoteArray#page like any property.

To update records when a page property changes:

Ember.Controller.extend({
  // the content property represents a paged array
  page: Ember.computed.alias('content.page'),
});

In older versions of Ember you would have done:

Ember.Controller.extend({
  // the content property represents a paged array
  pageBinding: 'content.page',
});

Lock to range

An example scenario where this will be useful:

Say you're dealing with realtime content. content.length is 20, perPage is 10 and you're on the second page. At some point content.length drops to 9. Calling lockToRange, ideally in the consuming component's init hook, will take you to automatically to the first page and update page-numbers accordingly.

init() {
  this._super(...arguments);
  get(this, 'pagedArray').lockToRange();
}

otherParams

PagedRemoteArray takes an optional otherParams arg. These params will be passed to the server when the request is made.

var paged = PagedRemoteArray.create({
  store: store,
  modelName: 'number',
  page: 1,
  perPage: 2,
  otherParams: { name: 'Adam' },
});

// server will receive params page=1, perPage=2, name=Adam

paramMapping

PagedRemoteArray takes an optional paramMapping arg. This is a hash that allows you to change the param names for page/perPage/total_pages.

Note that the default param name for perPage is per_page.

page and perPage control what is sent to the backend. total_pages controls where we expect to find the total pages value in the response from the backend.

// This will send a request with pageNum and limit params,
// and expect a response with a num_pages param in the meta.
var paged = PagedRemoteArray.create({
  /* ..., */
  paramMapping: { page: 'pageNum', perPage: 'limit', total_pages: 'num_pages' },
});

Other

Testing

We include some helpers to make testing pagination easier.

The helper used here is responseHash, in the context of a Pretender definition.

It takes the request, all fixtures, and the model name, and returns the appropriate response (with meta tag).

import Todo from '../../models/todo'
import Helpers from 'ember-cli-pagination/test-helpers'

c = ->
  server = new Pretender ->
    @get "/todos", (request) ->
      res = Helpers.responseHash(request,Todo.FIXTURES,'todo')

      [200, {"Content-Type": "application/json"}, JSON.stringify(res)]

export default c

Setup Paginated Rails API

# Gemfile
gem 'kaminari'
# controller
# I'm fairly sure you shouldn't need to set the meta manually, but for now that's what I'm doing.

class TodosController < ApplicationController
  def index
    page = (params[:page] || 1).to_i
    todos = Todo.page(page).per(10)
    render json: todos, meta: {total_pages: todos.total_pages}
  end
end

Contributors

You guys rock!

  • @broerse
  • @robdel12
  • @samselikoff
  • @pedrokiefer
  • @gcollazo
  • @johanneswuerback
  • @tonycoco
  • @dlameri
  • @piotrpalek
  • @robertleib
  • @halfdan
  • @bschnelle
  • @mcm-ham
  • @jcope2013
  • @thejchap
  • @sarupbanskota
  • @chrisccerami
  • @potato20
  • @aleontiev
  • @jeffreybiles
  • @fidlip
  • @lancedikson
  • @marceloandrader
  • @asermax
  • @balupton
  • @noslouch
  • @irruputuncu
  • @thomaswelton
  • @brentdanley
  • @pleszkowicz
  • @mixonic
  • @chrisdevor
  • @MichalBryxi
  • @flyrev
  • @armiiller
  • @artemgurzhii
  • @iezer
  • @jlami
  • @synaptiko
  • @rinoldsimon
  • @fivetanley

ember-cli-pagination's People

Contributors

addisong avatar armiiller avatar artemgurzhii avatar asermax avatar balupton avatar broerse avatar bschnelle avatar corincerami avatar fivetanley avatar flyrev avatar halfdan avatar iezer avatar irruputuncu avatar jcope2013 avatar jlami avatar johanneswuerbach avatar lancedikson avatar marceloandrader avatar mcm-ham avatar mharris717 avatar michalbryxi avatar mixonic avatar pedrokiefer avatar pierrickrouxel avatar pleszkowicz avatar rinoldsimon avatar samselikoff avatar synaptiko avatar thejchap avatar tonycoco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ember-cli-pagination's Issues

Paginate a filtered collection

Say I return this.store.find('post') from my route, but I want to paginate filteredPosts:

//controllers-posts
filteredPosts: Ember.computed.filterBy('isPublished')

Is this possible? Can I create a PagedArray without using the route mixin?

Allow to customize pagination meta data

At the moment there is no way to customize the total_pages meta property name. I would nice to be able to customize this.

Workaround:

import JsonApiSerializer from 'ember-json-api/json-api-serializer';

export default JsonApiSerializer.extend({
  extractMeta: function(store, type, payload) {
    if (payload && payload.meta) {
      if (payload.meta.totalPages) {
        // change meta data response
        payload.meta.total_pages = payload.meta.totalPages;
      }
      store.metaForType(type, payload.meta);
      delete payload.meta;
    }
  }
});

Need Help Setting Up Routing

I am not using the CLI, and I am trying to use the remote version in my app using the fixture adapter for now, I am confused on how to set up the index resource so that it recieves the params properly

App.Router.map(function() {
  this.resource('patients');
});

App.PatientsRoute = Ember.Route.extend(App.PageRouteMixin, {
    model: function(params) {
        return this.findPaged('patient', params);
    }
});

do I need to pass params on the resource's path?

I got the local adapter working fine doing the above so maybe it has to do with the fixtureAdapter?

Configurable defaults

Fir thank you for building this great addon and finally having a central place for pagination :-)

Currently a lot of things can be configured per router #43, page size, etc. Would it be possible to add a global config setting for those?

I'm currently working on an admin dashboard with several different paginated lists and all have the same settings.

Compatibility with django tastypie meta

Django tastypie has the following meta:

meta: {
  limit:15, 
  next:/api/v1/client/?limit=15&offset=16, 
  offset:1, 
  previous:null, 
  total_count:38
}

Using params.paramMapping works for translating the keys, but I cannot write that total_pages = total_count / limit + 1, nor can I write that offset is (page - 1) * limit + 1 and page is (offset - 1) / limit + 1. (I have not checked the math, but it's something like that).

The easy way out would be creating a paged-remote-tastypie-array.js, implementing just this, but that doesn't seem to be the best solution. Maybe the possibility for calling a function while mapping/unmapping could solve this.

I can try to get a patch for this, just would like to hear what would fit better here first.

How to not reload model everytime route changes

Whenever I change a page, the request is made, even if I browse back to route that the model is already loaded for. Is there a way to not request already loaded model? I also have an extra query parameter tab and it also reloads the model whenever it changes, can I make it so that it loads the model once?

// Route
export default Ember.Route.extend(RouteMixin, {
  queryParams: {
    tab: {
      refreshModel: true
    }
  },
  model: function(params) {
    params.paramMapping = {
      perPage: "size"
    };
    return this.findPaged('article', params);
  }
});

Here's a sample network output:

articles?page=4&size=10&tab=active
articles?page=5&size=10&tab=active
articles?page=4&size=10&tab=active

See page=4 is loaded twice.

pagedContent always Empty + page-numbers with NaN

I followed the guide on the readme, but my pagedContent always evaluates to the else, meaning that it is an empty array; in addition, I get NaN on my pagination:

image

My template:

{{#each pagedContent}}
        <dl class="blog-list">
            {{#each}}
                <dt class="blog-list-date">{{ago lastModified}}</dt>
                <dd class="clog-list-link">
                    {{#link-to "posts.post" this title = "post"}}{{title}}{{/link-to}}
                </dd>
            {{else}}
                <dd>No blog posts found</dd>
            {{/each}}
        </dl>
    {{else}}
        {{#alert-message type="error"}}
            <p>No posts found</p>
        {{/alert-message}}
    {{/each}}
{{page-numbers content=pagedContent}}

My controller:

PostsController = Ember.ArrayController.extend(
    # setup our query params
    queryParams: [
        "page"
        "perPage"
    ]

    # can be called anything, I've called it pagedContent
    # remember to iterate over pagedContent in your template
    pagedContent: pagedArray("content",
        pageBinding: "page"
        perPageBinding: "perPage"
    )

    # binding the property on the paged array
    # to a property on the controller
    totalPagesBinding: "pagedContent.totalPages"
)

Using the Ember inspector, I have verified that PostsController.get("pagedContent.content") contains the 14 items that currently exist in my store. Yet attempting PostsController.get("pagedContent")[0] yields null.

Not sure if this is a bug, but any help would be appreciated.

Readme file

The readme file doesn't reference the version of ember cli pagination which you get if you download it from NPM (by doing npm install ember-cli-pagination --save-dev). Particulary the "paginationType" config is different in master, which can be quiet confusing. Imo the readme should either show how to get the latest version (master) or be consistent with the version which you get from npm.

page-numbers component having trouble handling a blank Array

for some reason, it showing page 1 then page 0 when I have no records and have a blank Ember Array, the case where I have a blank ember array is on the table search when no records are returned

records = Em.A([]);
{{page-numbers content=records}}

another case where I see the same thing is when my PagedRemoteArray returns no records and totalPages is 0

screen shot 2014-11-18 at 11 58 10 pm

how to reload the model

Hi there, this is not an issue, more like a question.
I have two more fields that goes to the server which are:
Order and Filter.

I would like to reload the model everytime user changes order or press enter on filter.
I was not able to use this.get('model').reload();
It is already working if i change the filter or order and after i change the page, params are sent ok, but i would like to reload when the user change any of this fields with an "observes".

How can it be done?

perPage config doesn't work

When I change the perPage config nothing changes (still shows 10 items per page even when I configure 2 or 5)

Adding Pagination on Ember Data HasMany Links using PagedRemoteArray

in my afterModel I do something like this

 var parentRecordType = model.constructor.typeKey;
 var parentRecordId = parseInt(model.id, 10);
 var invoicesOptions = { parentRecordType: parentRecordType, parentRecordId: parentRecordId, modelName: 'invoice', store: this.store, page: 1, perPage: 10 };

 return Ember.RSVP.hash({
       filteredInvoices: PagedRemoteArray.create(invoicesOptions),
  });

I made some moderations to the fetchContent method in paged-remote-array.js

    var parentRecordType = this.get('parentRecordType');
    var parentRecordId = this.get('parentRecordId');
    var ops = this.get('paramsForBackend');
    var res;
    var url;

    if( Ember.isEmpty(parentRecordType) || Ember.isEmpty(parentRecordId) )
    {
        res = store.find(modelName, ops);
    }
    else
    {
       url = store.adapterFor(parentRecordType).buildURL(parentRecordType, parentRecordId) + '/' + store.adapterFor(parentRecordType).pathForType(modelName);
       res = Ember.$.get(url, ops);
    }

this will allow me to add add /patients/1/ to the url before invoices

// WHAT I WANT: http://localhost:3000/api/v1/patients/1/invoices?page=1&per_page=10

the tricky thing is I can't do

res = Ember.$.get(url, ops);

as I get this error back

Uncaught Error: Assertion Failed: ArrayProxy expects an Array or Ember.ArrayProxy, but you passed object 

debugging into ember data shows me

store.find(modelName, ops) goes into  findQuery and returns a promiseArray

I am pretty sure I will be to get this working with some more code but any suggestions on the best way to add pagination on has many links depending on the page I visit?

How to truncate pages properly?

When I use this addon,

Page 1 shows 1 2 3 4 5 6 10
Page 2 shows 1 2 3 4 5 6 7 10
Page 3 shows 1 2 3 4 5 6 7 8 10

what I want is the same behaviour as this.

So there are three different truncation strategies:

In the beginning:
1 2 3 4 5 ... 999
In the middle:
1 ... 3 4 5 ... 999
In the end:
1 ... 995 996 997 998 999

How is this possible?

NaN in the pagination browser

Hi,

I'm having a problem with the pagination buttons.
My backend comes from Laravel and not from Ruby so I'm not a 100% sure if it is correct, but I can't finy any information about this and tried to rebuild it as accurate as I could.

{"meta":{"total_pages":3},
"companies":[{"id":"1","aktiv":true,"name":"test1"},
             {"id":"2","aktiv":true,"name":"test2"},
             {"id":"3","aktiv":true,"name":"test3"},
             ...]
}

What am I doing wrong?
I followed your "Remote Paginated API" guide and I get the right amount of entries, but the Buttons don't work.

I think a short excerpt of a working json return, would be great for the guide. :)

thank you

Show loading spinner while model is loading

Hi,
before using your pagination, i use to have a loading var on my controllers set to false, whenever i changed the model i would set this loading to true and to false again on the promise return, success/fail method(i mean "save().then(success, fail)"), so i can show a loading spinner on the view(just in the table area) while model is loading.

Question is, how can i implement this with this pagination?
i thought something like this:

var loading = false,
fetchContent: function() {
    this.set('loading', true);
    res.then(function(rows) {
        this.set('loading', false);
    }
}

then in my template:

{{#if loading}}
<!-- Show loading -->
{{else}}
<!-- List entries -->
{{/if}}

I intend to use a reopen(paged-remote-array) on a mixing to add this implementation.
Thank you.

Feature Request: custom property names

In the private API for the app I'm building, we use page, limit, and total_pages. I'd like to be able to declare these as the query params. Can you add the ability to declare these?

Developer docs

I'd like to help out, in particular work on making findPaged a promise. I don't know how to get my dev environment running. The Rakefile requires a gem called mharris_ext, is that local? On github? If we're going to use Rake for building, we should use a Gemfile. Not sure ruby is best build tool here, as we're really in the node ecosystem now.

Anyway, if you can fill me in I'd be happy to update the docs with some instructions. But I need

  • findPaged to be a promise
  • to get sorting/filtering figured out

and am happy to help if I can get going.

cs

I think I remember catching wind of dropping CS. Maybe it was only dropping CS requirements?

Anyway, I think this plugin would benefit if it was written in JS for a few reasons:

  • smaller footprint
  • es6 features going forward
  • cs is falling out of favor in the community

What are your thoughts/plans on this?

Use PagedRemoteArray in a similar fashion to Em.A()?

is it possible to pass in a regular array into PagedRemote Array? or is there a way to do this in a different way? basically the use case is I am filtering the records in a table on a remote call to the server, converting the recordArray returned back to a regular array to do some things then converting it back to a recordArray at the end

something like this

  var filteredPagedArray = App.PagedRemoteArray.create({
          array: ac
          page: params.page,
          perPage: params.perPage
     });

    this.set('filteredRecords',  filteredPagedArray);

right now I am doing something like this in my app

  this.set('filteredRecords', Em.A(ac));

Unique Model/ Route, Route with :id

in my route im returning a list of products (v1/products?per_page=40):

return PagedRemoteArray.create({modelName: 'product',
                                    store: this.store,
                                    page: params.page || 1,
                                    perPage: params.per_page || 10});
  },

But, I wanted to apply the pagination to a unique route(v1/store/:id/products??per_page=40)

return PagedRemoteArray.create({modelName: '?',
                                    store: ?,
                                    page: params.page || 1,
                                    perPage: params.per_page || 10});
  },

Not sure how to get there without an error in the store or ModelName.

requirements

Not sure why I added the .44 requirement, I think I thought that was when addons became supported, but wasn't it earlier?

What's the actual version req for ember-cli-pagination?

Error util.js reference

Getting a error there is a reference to a util folder but when i run the npm install there is not util folder

Scroll Pagination/ Inifiniti Scroll

Can't seem to apply the enhancement tab, but you have a few approaches you can use. I like the PagedRemoteArray because of the amount of data I load.
So you can either update the page or the per_page for the bottom action of the scroll. the page will load the next pages losing the current items. the per_page will append items.
I created a getMore action and decided to update the per_page as the scroll hits the bottom.
getMore: function(obj) {
var pagedArray = this.get('content');
var controller = this;
function returnPerPage(){
var cPerPage = controller.get('per_page')+5;
return cPerPage;
}
pagedArray.set("perPage",returnPage());
}
So now the now every-time the action hits it takes the current per_page and adds 5 more items.
I call this action in the view where my scrollbar is looking for a callback. Since there are so many methods of doing the scrollbar I'm sure they all have a bottom callback. and i set the callback to the controller action with:
this.get('controller.controllers.another').send('getMore');
http://www.kaspertidemann.com/calling-a-controller-action-from-a-view-via-the-needs-api-in-ember-js/

Not sure how this can be built as an addon but it can also be hacked together for quick usage now.

Getting started

Having trouble getting started. I added the component, set the paginationType to local, and added the Controller mixin. The component seems to be rendering an empty <ul>.

What's the next step?

Remote pagination, http calls send twice

I implemented the remote pagination and everything works as expected, but all http calls after the first page are send twice.

OPTIONS places?page=2&per_page=25
OPTIONS places?page=2&per_page=25
GET places?page=2&per_page=25
GET places?page=2&per_page=25

"Uncaught RangeError: Maximum call stack size exceeded" when underlying array changes size

Thanks for this add-on!

https://gist.github.com/07d143daf5617770fb96.git

Everything works great, until I change the category or search query (which can affect the totalPages count).

After that, I usually can't click last page, and when I click around the pages, I hit "Uncaught RangeError: Maximum call stack size exceeded" and everything is busted until a refresh.

I can change the sort order just fine, paging still works. It only breaks after I call one of the actions that filters the array.

Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.