Ilia Choly
Ilia Choly

Reputation: 18557

Ember.js CollectionView order

I have an ArrayController which is periodically updated. It has a sorted computed property which keeps things in order. I'm trying to use a CollectionView with it's content property bound to the sorted property, but it's not rendering them in the correct order. demo

I've obviously made the false assumption that order is maintained between the content and childViews property. What is the correct way to do this?

Handlebars:

<script type="text/x-handlebars" data-template-name="item">
    id {{view.content.id}}
</script>

<script type="text/x-handlebars">
    <ul>
     {{collection
        contentBinding="App.itemController.sorted"
        itemViewClass="App.ItemView"
    }} 
    </ul>        
</script>

JavaScript:

​App = Ember.Application.create({
    ready: function(){

        // add a new object with a random id
        // every second
        setInterval(function(){

            var id = Math.round(Math.random() * 100),
                obj = Em.Object.create({ id: id });
            App.itemController.pushObject(obj);

        }, 1000);

    }
});

// Collection Item View
App.ItemView = Em.View.extend({
    tagName: "li",
    templateName: "item"
});

App.itemController = Em.ArrayController.create({

    // random order
    content: Em.A([
        Em.Object.create({ id: 5 }),
        Em.Object.create({ id: 3 }),
        Em.Object.create({ id: 10 }),
        Em.Object.create({ id: 6 }),
        Em.Object.create({ id: 1 }),
        Em.Object.create({ id: 2 }),
        Em.Object.create({ id: 100 }),
    ]),

    // filtered content
    sorted: function(){
        return this.get('content').sort(function(a,b){
            return a.get('id') - b.get('id');
        });
    }.property("@each")

});

Upvotes: 4

Views: 2600

Answers (2)

sly7_7
sly7_7

Reputation: 12011

Inspired by this answer: ember.js #each order by property

I use the sorting properties of ArrayController: https://github.com/emberjs/ember.js/blob/master/packages/ember-runtime/lib/mixins/sortable.js

I don't use CollectionView, but a simple #each, and call to addObject instead of pushObject

template

<script type="text/x-handlebars" data-template-name="item">
    id {{view.content.id}}
</script>

<script type="text/x-handlebars" data-template-name="application">
    <ul>
     {{#each item in App.itemController}}
        {{view App.ItemView contentBinding="item"}}
     {{/each}} 
    <li>        
</script>

javascript

App = Ember.Application.create({
  ready: function() {

    // add a new object with a random id
    // every second
    setInterval(function(){
        var id = Math.round(Math.random() * 100),
            obj = Em.Object.create({ id: id });
        // should call addObject, because pushObject does not sort the inserted item
        //App.itemController.pushObject(obj); 
        App.itemController.addObject(obj);
    }, 1000);
  }       
});

// Collection Item View
App.ItemView = Em.View.extend({
  tagName: "li",
  templateName: "item"
});

App.itemController = Em.ArrayController.create({
  sortProperties: ['id'],
  // random order
  content: Em.A([
    Em.Object.create({ id: 5 }),
    Em.Object.create({ id: 3 }),
    Em.Object.create({ id: 10 }),
    Em.Object.create({ id: 6 }),
    Em.Object.create({ id: 1 }),
    Em.Object.create({ id: 2 }),
    Em.Object.create({ id: 100 }),
  ]),
});
App.ApplicationView = Ember.View.extend({
  templateName: 'application'
});
App.ApplicationController = Ember.Controller.extend();
App.Router = Ember.Router.extend({root: Em.Route.extend()});
App.initialize();​

The jsfiddle: http://jsfiddle.net/Sly7/LJAYk/

Upvotes: 5

pangratz
pangratz

Reputation: 16163

For the sake of completeness to @sly7_7's correct answer, here is a version with CollectionView, see http://jsfiddle.net/pangratz666/ctPAA/.

Handlebars:

<script type="text/x-handlebars">
    {{collection
        tagName="ul"
        contentBinding="App.itemController"
        itemViewClass="App.ItemView" }} 
</script>

JavaScript:

App.itemController = Em.ArrayController.create({

    sortProperties: 'id'.w(),

    // random order
    content: Em.A([
        ...
    ])

});

Upvotes: 7

Related Questions