Search code examples
ember.jspaginationember-cli

"Load more" content from the server and add it to the page


I've waded through a lot of pages/questions regarding pagination/infinite scrolling/load more content.

Either the content is pre-loaded completely in the store or the examples requesting new data simply don't work.

I've got a blog displaying 5 posts then a 'load more' button. Upon hitting this button I'd like to request 5 more posts from the server and add them live to the page.

this.store.find('post', {limit: 5, offset: 5, sort:'createdAt desc'});

Please can you provide a working example or instructions to make it work?

EDIT: the following seems to be a good option but I don't know how to make it work

Make the model a standard array and use the route hooks and "load more" actions to fill it with records from ED query results

EDIT2 this is how I set the model for the route:

import Ember from 'ember';

export default Ember.Route.extend({
   model: function() {
      return this.store.find('post', { isPublished: true,
                                       limit: 5,
                                       sort:'createdAt desc'});
   }
});

Solution

  • I've created a simple app for you on GitHub:

    https://github.com/andrusieczko/ember-loadMore-example

    Just fetch it, install dependencies and you're ready to go:

    $ git clone https://github.com/andrusieczko/ember-loadMore-example.git
    $ cd ember-loadMore-example
    $ npm install
    $ bower install # possibly you don't have to do that
    $ npm start
    

    and go to http://localhost:4200 where you have a link to #/post route.

    I've presented how you can do loadMore button but I set up the offset variable as well, so you can easily transform this code to the pagination.

    So, in my routes/post.js file I've got two query params defined (though in this example I'm actually using only limit):

    export default Ember.Route.extend({
      queryParams: {
        limit: {
          refreshModel: true
        },
        offset: {
          refreshModel: true
        }
      },
    
      model: function(params) {
        return this.store.find('post', {
          limit: params.limit,
          offset: params.offset
        });
      }
    });
    

    That sets up both of the query params. refreshModel: true causes fetching new data from server (model hook is called) whenever a query param is changed.

    To have it working, you have to also define your query params in the controller (controllers/post.js):

    export default Ember.Controller.extend({
      queryParams: ['limit', 'offset'],
      limit: 20,
      offset: 0,
    
      pageSize: 20,
    
      actions: {
        loadMore: function() {
          this.set('limit', this.get('limit') + this.get('pageSize'));
        }
      }
    });
    

    And the loadMore action is just adding the pageSize to existing limit.

    The template (templates/post.hbs) look like that:

    <h1>Posts</h1>
    
    <ul>
      {{#each post in model}}
        <li>{{post.id}}. {{post.name}}</li>
      {{/each}}
    </ul>
    
    <button {{action 'loadMore'}}>Load more</button>
    

    To have the fully working example, I've created a simple server side that can understand limit and offset:

    app.get('/api/posts', function(req, res) {
      var limit = parseInt(req.query.limit);
      var offset = parseInt(req.query.offset) || 0;
    
      var filteredItems = items;
      if (limit) {
        filteredItems = items.slice(offset, (offset+limit));
      } else {
        filteredItems = items.slice(offset);
      }
      res.send({
        post: filteredItems
      });
    });
    

    where items is an 100-elements array of [{id: 0, name: 'post0'},{id: 1, name: 'post1'},....

    Hence the model structure (models/post.js):

    export default DS.Model.extend({
      name: DS.attr('string')
    });
    

    I hope that it will help you to understand how to implement the solution in your project.

    Enjoy!