8

I'd like to be able to sort an ArrayController whose content arises from an ember-data query. Unfortunately, the sortProperty mixin doesn't seem to work in this case.

I'd like to be able to do the following:

App = Ember.Application.create();
App.store = DS.Store.create({ revision: 4});

App.Item = DS.Model.extend({
    id: DS.attr('string'),
    name: DS.attr('string')
});

App.store.createRecord(App.Item, {id: '4', name: 'banana' });
App.store.createRecord(App.Item, {id: '2', name: 'apple'});
App.store.createRecord(App.Item, {id: '6', name: 'spaghetti'}); 

App.ItemsController = Ember.ArrayController.create({
    content: App.store.findAll(App.Item),
    sortProperties: ['name']
});

With the latest version of Ember and Ember-data, this gives the output:

[ id: 4, name: banana ]

[ id: 2, name: apple ]

[ id: 6, name: spaghetti ]

The issue here is that App.store.findAll() returns a RecordArray whose content property is not simply an array of App.Item instances (in this case, content is [2, 3, 4])

To actually get my hands on the instances I need to use something like objectAt(). But even if I extract the App.Item instances from the RecordArray and dump them in an ordinary array, things don't work as expected.

Am I missing the obvious way to do this, or is this just the present state of the framework? I'd rather not have to replicate all of my models as plain objects just to sort them.

EDIT:

I got around the issue by making my own custom ArrayController. Still, it would be nice if things worked as above.

EDIT #2:

Original Handlebars template:

<script type="text/x-handlebars">
    {{#each App.ItemsController.content }}
        <p>[ id: {{id}}, name: {{name}} ]</p>
    {{/each}}
</script>

(Also, I had used a sortProperty property instead of sortProperties in my code above, but that was just a typo.)

And yes, if one instead uses

<script type="text/x-handlebars">
    {{#each App.ItemsController.arrangedContent }}
        <p>[ id: {{id}}, name: {{name}} ]</p>
    {{/each}}
</script>

Then we get exactly what we want:

[ id: 2, name: apple ]

[ id: 4, name: banana ]

[ id: 6, name: spaghetti ]
1
  • 5
    I'm sorry, you haven't done a particularly good job of explaining what's not working here, can you please put your handlebars template in. I think there's a small issue where sometimes you have to bind to the arrangedContent value of the ArrayController to get the correctly ordered objects. Commented Sep 23, 2012 at 15:13

4 Answers 4

11

I had the same problem. Took me a while, but eventually this general solution solved it:

App.ArrayController = Ember.ArrayController.extend({
  sortProperties: ['id'],
  sortAscending: true,

  sortedContent: (function() {
    var content;
    content = this.get("content") || [];
    return Ember.ArrayProxy.createWithMixins(Ember.SortableMixin, {
      content: content.toArray(),
      sortProperties: this.get('sortProperties'),
      sortAscending: this.get('sortAscending')
    });
  }).property("content.@each", 'sortProperties', 'sortAscending'),

  doSort: function(sortBy) {
    var previousSortBy;
    previousSortBy = this.get('sortProperties.0');
    if (sortBy === previousSortBy) {
      return this.set('sortAscending', !this.get('sortAscending'));
    } else {
      set('sortAscending', true);
      return this.set('sortProperties', [sortBy]);
    }
  }
});

Now most of my ArrayControllers extend App.ArrayController instead of Ember.ArrayController, in particular the ones that have Ember/Data RecordArrays as content.

Now, in your handlebar templates, do this:

 {{#each item in sortedContent}}
   ...          
 {{/each}}

instead of

 {{#each item in content}}
   ...          
 {{/each}}
Sign up to request clarification or add additional context in comments.

2 Comments

I'm accepting this since it resolves my problem, but as Bradley Priest indicated above, binding to arrangedContent is sufficient.
Just a note, I found that using an ArrayController instead of an ArrayProxy w/ mixin worked for me. I'm not sure what other side effects it has, but it works flawlessly. I have read that ArrayController is actually ArrayProxy with the mixins, but it doesn't seem to behave that way.
6

As of Ember 1.1.2 and ember-data 1.0.0-beta.3, and probably earlier, just setting sortProperties on the Controller is enough. sortAscending can be set to true or false depending on which direction you want to sort.

App.ArrayController = Ember.ArrayController.extend({
  sortProperties: ['name'],
  sortAscending: true
})

However, note that

sortProperties: ['id']

appears to sort lexically rather than numerically. I got around the lexical sorting by a created_at timestamp, but there may be another way around it.

2 Comments

can sortProperties be changed dynamically after load? and how do you choose ascending or descending?
Added in reference to sortAscending. Also, as far as changing the sorting dynamically, it looks like that is possible -- stackoverflow.com/questions/12476682/…
4

I had a similar issue and sorted it out via the docs for the array class
in my route I used the sortBy() method. so in your case it might be something like

App.store.findAll().sortBy('name');

I know this is an old question but answering it in case someone, like myself stumbles on by

3 Comments

this.store.findAll('todo-list').sortBy('name') is returning an empty array on my end, not sure why.
does removing the sortBy() make a difference? what property are you trying to sort by?
This is my code var todoLists = this.store.findAll('todo-list').sortBy('name');. If I remove the sortBy(), the results are correct. The Model I'm getting is github.com/LouWii/ember-todo-list-app/blob/master/app/models/… (the whole project is on that Github repo actually).
3

As of Ember version 1.0.0-rc.4 Ember.ArrayProxy.create(Ember.SortableMixin .... doesn't seem to work anymore. Use Ember.ArrayProxy.createWithMixins(Ember.SortableMixin .... or use the built-in sorting functionalities in Ember.ArrayController.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.