redress
redress

Reputation: 1449

Sorting Backbone collections prior to render

EDIT: To sort a Backbone Collection, you simply need to specify a comparator (without defining a sortBy mechanism) as follows: dictionary.add(entry); dictionary.comparator = 'word';


I am having trouble sorting a collection that new models are pushed to using .add(), (not pre-loaded). Ive tried to use underscore's sort method below

 var sorted = _(dictionary).sortBy("word");

but I can't get the collection to respond. Below is my code. Ive commented out my non-functioning code at the bottom.

(function($){

    //---------SINGLE ENTRY MODEL----------
            var Entry = Backbone.Model.extend({
                defaults: function(){
                    return{
                        word: '',
                        definition: ''
                    }
                }
            });

        //------------ENTRY MODEL COLLECTION------------
            var EntryList = Backbone.Collection.extend({
                model: Entry
            });

        //-----INSTANCIATE COLLECTION----
        var dictionary = new EntryList();

        //-----SINGLE ENTRY VIEW------
        var EntryView = Backbone.View.extend({
            model: new Entry(),
            tagName:'div',

            events:{
                'click .edit': 'edit',
                'click .delete': 'delete',
                'keypress .definition': 'updateOnEnter'
            },

            delete: function(ev){
                ev.preventDefault;
                dictionary.remove(this.model);
            },

            edit: function(ev){
                ev.preventDefault;
                this.$('.definition').attr('contenteditable', true).focus();

            },
            close: function(){
                var definition = this.$('.definition').text();
                this.model.set('definition', definition);
                this.$('.definition').attr('contenteditable', false).blur();

            },

            updateOnEnter: function(ev){
                if(ev.which == 13){
                    this.close();
                }
            },

            initialize: function(){
                this.template = _.template($("#dictionary_template").html());

            },

            render: function(){
                this.$el.html(this.template(this.model.toJSON()));
                return this;
            }
        });

        //--------------DICTIONARY VIEW------------
        var DictionaryView = Backbone.View.extend({
            model: dictionary,
            el: $('#entries'),

            initialize: function(){
                this.model.on('add', this.render, this);
                this.model.on('remove', this.render, this);

            },

            render: function(){
                var self = this;
                self.$el.html('');
                _.each(this.model.toArray(), function(entry, i){
                    self.$el.append((new EntryView({model: entry})).render().$el);
                });

                return this;
            }
        });


        //-------BINDING DATA ENTRY TO NEW MODEL VIEW-------
        $(document).ready(function(){
            $('#new-entry').submit(function(ev){
                var entry = new Entry({word: $('#word').val(), definition: $('#definition').val() });

                dictionary.add(entry);

                //var sorted = _(dictionary).sortBy("word");
                //console.log(sorted.toJSON());

                console.log(dictionary.toJSON());

                $('.form-group').children('input').val('');

                return false;
            });
            var appView = new DictionaryView();
        });
    })(jQuery);
</script>

Upvotes: 2

Views: 685

Answers (1)

seebiscuit
seebiscuit

Reputation: 5053

I think your problem is that you're applying a straight-Underscore.js sortBy to dictionary which is not a collection in the sense Underscore.js understands it. Rather it's a Backbone.Collection (and it doesn't help you that J. Ashkenaz wrote both Backbone and Underscore.js). So, unfortunately, running sortBy on dictionary is going to give you unpredictable results (since you have all kinds of other parent properties on a Backbone.Collection besides the models prop. So...

Using sort

I think the easiest and probably most stable solution is to use Backbone.Collection.sort(). The beauty of it all is that once you provide a comparator the Backbone will sort the collection for you automatically (I'm not gibing you, check out the docs). (Btw, you can disable this functionality on Backbone.Collection.add(), by passing in { sort: false }.)

Using a comparator

According to the docs (emphasis mine):

A comparator can be defined as a sortBy (pass a function that takes a single argument), as a sort (pass a comparator function that expects two arguments), or as a string indicating the attribute to sort by.

In your case if you add the line

dictionary.comparator = "word";

before your first add function (like after your instantiate the collection) you should be all set.

Upvotes: 3

Related Questions