The best way to sort a collection in a CompositeView
Asked Answered
D

3

14

I am trying to sort a collection in a Marionette.CompositeView.
I have a collection which looks like this:

[
   {id: 1, name: 'bar'},
   {id: 2, name: 'boo' },
   {id: 3, name: 'foo' }
]

I need to sort the collection by id in reverse order.
Actually it work only when I reload the page.
When I add a new model, the new item is added apparently random to the list.
If I refresh the page, they will be well sorted.

My questions are:
1) how to fix the problem when I add a new model?
2) it will be possible to improve the code?


Here is my code:

return Marionette.CompositeView.extend({

    initialize: function () {
        this.collection.fetch();
    },

    onRender: function () {
        var collection =  this.collection;

        collection.comparator = function (collection) {
            return - collection.get('id');
        }
    },

    onSuccess: function () {
        this.collection.add(this.messageModel);
        this.collection.sort(); // the messageModel seems to be added 
                                // apparently randomly to the list. 
                                // only if I refresh the page it will be ok
    }
})
Dropout answered 25/7, 2012 at 21:8 Comment(0)
P
14

For Marionette >= 2.0, CollectionView and CompositeView maintain sorting by default.

For Marionette < 2.0 and >= 1.3.0:

var MySortedView = Backbone.Marionette.CollectionView.extend({

  // ...

  appendHtml: function(collectionView, itemView, index) {
    // Already sorted when buffering.
    if (collectionView.isBuffering) {
      Backbone.Marionette.CollectionView.prototype.appendHtml.apply(this, arguments);
    }
    else {
      var childrenContainer = $(collectionView.childrenContainer || collectionView.el);
      var children = childrenContainer.children();
      if (children.size() === index) {
        childrenContainer.append(itemView.el);
      } else {
        childrenContainer.children().eq(index).before(itemView.el);
      } 
    }
  }

});

For Marionette < 2.0 or < 1.3.0 (same as before without buffering):

var MySortedView = Backbone.Marionette.CollectionView.extend({

  // ...

  appendHtml: function(collectionView, itemView, index) {
    var childrenContainer = $(collectionView.childrenContainer || collectionView.el);
    var children = childrenContainer.children();
    if (children.size() === index) {
      childrenContainer.append(itemView.el);
    } else {
      childrenContainer.children().eq(index).before(itemView.el);
    } 
  }

});

It's the same for CollectionView and CompositeView.

Premer answered 26/7, 2012 at 6:37 Comment(4)
the github link is dead :-(Cowling
the github link is not dead anymore :-)Rella
Github link is again dead.Corneille
The wiki was removed, because V2 is now the standard library which handles this.Jhansi
C
3

I believe the Marionette guys are considering building this into Marionette, but until that time, I've build a little mixin called Sorted which you can mix into your CollectionView and CompositeView classes. It's been heavily used in a production environment for Gitter for a long time and we find it works very well..

Christean answered 2/4, 2014 at 18:17 Comment(0)
S
1

Can you declare the .comparator when you create the collection? from your code the .comparator exists only on local variable var collection inside onRender function. If defined correctly the collection must be automatically sorted and you do not need to call .sort after adding new model

var Chapters = new Backbone.Collection({
    comparator = function(chapter) {
        return chapter.get("id");
    };
});
Sweptback answered 26/7, 2012 at 0:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.