# "Load More" data using ember-data and find queries

**URL:** <https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998>\
**Category:** Ember Data\
**Created:** [January 28, 2014, 3:49am UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998 "2014-01-28T03:49:39Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![MichaelO](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@MichaelO](https://discuss.emberjs.com/u/MichaelO)\
**Post date:** [January 28, 2014, 3:49am UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/1 "2014-01-28T03:49:39Z")

</div>

Hi everyone! I have only been working with ember and ember-data for about a week now, so please bear with me if this question is really silly.

I’ve been trying to implement a feature where the user can click a button to load more images. So, when the page first loads, only the first 10 images are displayed. The user clicks a “Load More” button, and 10 more are displayed, etc. But I am really stuck right now. I’ve spent the evening searching for solutions, but I can’t figure out what to do for the life of me.

So, my route’s initial model is fairly straightforward. I have just put random dummy data into the parameters list for brevity:

```
App.IndexRoute = Ember.Route.extend({
   model: function() {
      return this.store.find('event', {page: 1, perPage: 10, lat: 2, lng: 2});
   }
})

```

(Just to note: the query is dependent on the user’s location. I’m just pointing this out because I recall reading that sending parameters to the store’s find query affects the way the results are processed.)

I am able to get this data to load on the page no problem. The issue is when the user wants to load more images. In my controller, I have a “loadMore” action where I simply just increment the page by one and call find on the store again.

```
 loadMore: function() {
     // Increment page
     // 
     this.store.find('image', {page: page + 1, perPage: 10, lat: 2, lng: 2})
 }

```

Now, from my understanding, since these queries are using extra parameters, the model won’t automatically be updated with the new records, whereas if they were omitted, the model would reflect the changes. But since I can’t remove those parameters, how would I then add these additional records to my model? I tried doing it manually after the promise was resolved… so something like this:

```
var self = this;
var more = this.store.find('image', {page: page + 1, perPage: 10, lat: 2, lng: 2});
more.then(function() {
   self.pushObjects(more);
});

```

But this didn’t work. It threw an error because the model’s array is immutable.

I really hope this is making sense. I’m still learning everything, so it’s entirely possible that I am way off base here. Any help on how to resolve this would be greatly appreciated. I don’t even know if this is the best/correct approach, so any alternative suggestions are also happily welcome.

Thank you for your time.

Mike

---

<div class="post-metadata">

**Author:** ![MichaelO](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@MichaelO](https://discuss.emberjs.com/u/MichaelO)\
**Post date:** [January 28, 2014, 3:42pm UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/2 "2014-01-28T15:42:33Z")

</div>

After looking around more, I discovered that the syntax of my attempt was incorrect. I tried the following:

```
var self = this;
this.store.find('image', {params}).then(function(results) {
   self.pushObjects(results);
});

```

This also didn’t work (same reason: the model is immutable). What would be the correct approach to loading more records to an immutable model?

---

<div class="post-metadata">

**Author:** ![pablolmiranda](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/pablolmiranda/32/15457_2.png) [@pablolmiranda](https://discuss.emberjs.com/u/pablolmiranda)\
**Post date:** [January 29, 2014, 2:51pm UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/3 "2014-01-29T14:51:15Z")

</div>

I think you should be using this.store.findAll(‘image’, params), because this will generate a call to your API passing the params as query strings in the URL.

---

<div class="post-metadata">

**Author:** ![lookingsideways](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/lookingsideways/32/13652_2.png) [@lookingsideways](https://discuss.emberjs.com/u/lookingsideways)\
**Post date:** [January 29, 2014, 5:58pm UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/4 "2014-01-29T17:58:36Z")

</div>

I’ve run into the same issue. There are two solutions:

1. Make the model a standard array and use the route hooks and “load more” actions to fill it with records from ED query results
2. Set the model to a `store.filter` and have the other methods populate the store

I’ve resorted to using method 1 for my infinite scrolling/load more needs as method 2 can give you a sparsely populated list if you have been loading records in other parts of the app which makes pagination awkward.

There are some other topics worth reading:

> [@Pagination in Ember Data 1.0 beta](http://discuss.emberjs.com/t/pagination-in-ember-data-1-0-beta/2422):
>
> Hi, The previous way of handling pagination (up to v0.13) was to return a meta object as part of the response, but this functionality was removed (the whole extractMeta functionality in the default DS.JSONSerializer) Are any thoughts/ideas on how pagination will be handled in Ember Data 1.0 ? Is the meta object handling coming back? Thanks,

> [@Pagination with Ember Data - can we agree on a single solution?](http://discuss.emberjs.com/t/pagination-with-ember-data-can-we-agree-on-a-single-solution/742):
>
> In the spirit of the [Modal View topic](http://discuss.emberjs.com/t/modal-views-can-we-agree-on-a-best-practice/707/) let’s continue with pagination. It’s been discussed over and over that we need to somehow standardize this, but I think it would be a good idea to make this discussion public, and not just something on gtalk/campfire slight_smile I don’t think this is a question that belongs to SO, because what I’m looking for is a discussion of how different approaches to the problem and which one should be made a standardized solution. The option people seem to be taki…

> [@What is the proper use of store.filter / store.find for infinite scrolling?](http://discuss.emberjs.com/t/what-is-the-proper-use-of-store-filter-store-find-for-infinite-scrolling/3798):
>
> Hi all, I’m trying to implement an page with infinite scrolling and came across some trouble. First I will explain my current solution and I would like to know if this is the correct way to push things into the store. From my understanding the expected way to setup infinite scrolling is to set the controllers model to a store filter which is a live record array which will automatically be updated as more records are added like so: model: function (urlParams) { return this.get('store')…

---

<div class="post-metadata">

**Author:** ![MichaelO](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@MichaelO](https://discuss.emberjs.com/u/MichaelO)\
**Post date:** [January 30, 2014, 1:11am UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/5 "2014-01-30T01:11:58Z")

</div>

Hmm, I kind of like that store.filter approach. I might look into that later.

I came up with a solution… I think. I mean, everything is working on my page, but I don’t know if it’s the “correct” way or if there are any potential consequences.

What I did was define the model in the route like:

```
App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('image', params).then(function (results) {
       return results.content;
    }
 }
})

```

and then in the controller, the load more looks like:

```
loadMore: function() {
  var self = this;
  this.store.find('image', {params}).then(function(results) {
     self.pushObjects(results.content);
  }
});

```

Works like a charm so far, although I imagine I will lose flexibility later on.

Thank you for the responses!

---

<div class="post-metadata">

**Author:** ![radq](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/radq/32/4898_2.png) [@radq](https://discuss.emberjs.com/u/radq)\
**Post date:** [January 31, 2014, 2:39am UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/6 "2014-01-31T02:39:41Z")

</div>

I had a lot of pages that required implementing infinite scrolling, so I ended up defining a mixin that I would add to any route that needed pagination / infinite scroll:

```javascript
App.Paginated = Ember.Mixin.create({
  // Return an empty array immediately from the model hook.
  model: function() {
    this.set('cursor', null);
    return [];
  },

  // Wrapper around fetchPage which needs to be implemented by the route.
  // Keeps track of whether we are currently fetching a page, and saves the cursor
  // returned by the server.
  fetchPageProxy: function(cursor) {
    var self = this;
    this.set('currentlyFetchingPage', true);

    return this.fetchPage(cursor).then(function(objects) {
      self.set('cursor', objects.get('meta.cursor'));

      Ember.run.next(function() { self.set('currentlyFetchingPage', false); });

      if (objects.get('length') == 0) { self.setCanLoadMore(false); }
      else { self.setCanLoadMore(true); }

      return objects;
    });
  },

  // Set canLoadMore on the controller while setting it up.
  setupController: function(controller, model) {
    this.setCanLoadMore(true);
    controller.set('canLoadMore', this.get('canLoadMore'));
    controller.set('model', model);
  },

  // Set `canLoadMore` on the route and, if possible, on the controller.
  setCanLoadMore: function(canLoadMore) {
    this.set('canLoadMore', canLoadMore);
    if (this.controller) { this.controller.set('canLoadMore', canLoadMore); }
  },

  actions: {
    loadNextPage: function() {
      var that = this;
      if (this.get('canLoadMore') && !this.get('currentlyFetchingPage')) {
        this.fetchPageProxy(this.get('cursor')).then(function(objects) {
          that.controller.get('content').addObjects(objects);
        });
      }
    }
  }
});

```

Then in the route I only need to implement a `fetchPage` function:

```nohighlight
App.PaginatedRoute = Ember.Route.extend App.Paginated,
  fetchPage: (page) ->
    @store.find 'model', by_model: @modelFor('model').get('id'), page: page

```

---

<div class="post-metadata">

**Author:** ![shanson](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/shanson/32/11272_2.png) [@shanson](https://discuss.emberjs.com/u/shanson)\
**Post date:** [October 29, 2014, 8:49pm UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/7 "2014-10-29T20:49:41Z")

</div>

I was able to get basic pagination to work with the following. Not sure if it’s the best approach.

Route:

```auto
App.IndexRoute = Ember.Route.extend({
  model: function() {
    return this.store.find('image');
  }
}

```

In Controller:

```auto
loadMore: function() {
  var metaData = this.store.metadataFor('image');
  var params = { page: metaData.page+1, per_page: metaData.per_page };

  this.store.find('image', params).then(function(images) {
    self.get('model').addObjects(images);
  });
}

```

---

<div class="post-metadata">

**Author:** ![blazeeboy](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/blazeeboy/32/11310_2.png) [@blazeeboy](https://discuss.emberjs.com/u/blazeeboy)\
**Post date:** [August 29, 2015, 2:26pm UTC](https://discuss.emberjs.com/t/load-more-data-using-ember-data-and-find-queries/3998/8 "2015-08-29T14:26:17Z")

</div>

Thank you, this worked for me with some modifications, also i added this snippet of code to my route instead of controller, I don’t know where is the best place to add it.

```
    import Ember from 'ember';

    export default Ember.Route.extend({
      lastThreadsPage: false,
      limit: 25,
      offset: 0,

      model: function(){
        var self = this;
        return Ember.RSVP.hash({
          threads: this.store.find('thread', {
            limit: self.get('limit'),
            offset: self.get('offset')
          }),
          groups: this.store.findAll('group')
        });
      },

      actions: {
        loadMoreThreads: function() {
          var self = this;
          var params = {
            limit: this.get('limit'),
            offset: this.get('offset')+this.get('limit')
          };

          this.set('offset', this.get('offset') + this.get('limit'));

          this.store.find('thread', params).then(function(threads) {
            if(threads.content.length===0){
              self.set('lastThreadsPage', true);
            }
            self.currentModel.threads.addObjects(threads);
          });
        }
      }
    });

```
