0
votes

I render a collection of models, which is associated with a collectionView where when rendered each element in the collection has its own 'itemview' which is rendered.

When a collection is sorted and the listView re-rendered based on the new order, I had been creating a totally new view for each item, and as I was not clearing up any previous instances of views associated with that model, I believe zombies being left around.

So initially rendering my collection I would do...

render : function() {

    $(this.el).empty();
    var content = this.template.tmpl({});
    $(this.el).html(content);
    sortingView.el ='#sorting-container';       
    var els = [];       
    _.each(this.collection.models, function(model){                     
        var view = new TB_BB.RequestItemView({model : model});
        els.push(view.render().el);
    });
    $('#request-list').append(els);
    sortingView.render();

    return this;
}

So whenever the render function was called a second/third etc time, I had not cleared up the TB_BB.RequestItemView (hence the zombies)

To overcome this I tried to add some simple caching in the collections view, so that instead of creating a new itemview if it had already been created use that instead. My code

initialize : function(){
    _.bindAll(this,"render");
    this.collection.bind("add", this.render);
    this.collection.bind("remove", this.render);
    this.template = $("#request-list-template");
    this.views = {};
},
events : {
    "change #sort" : "changesort",      
    "click #add-offer" : "addoffer",
    "click #alert-button" : "addalert"
},
render : function() {
    $(this.el).empty();
    outerthis = this;
    var content = this.template.tmpl({});
    $(this.el).html(content);
    sortingView.el ='#sorting-container';       
    var els = [];       
    _.each(this.collection.models, function(model){
        var view;
        if(outerthis.views[model.get('id')]) {
            view = outerthis.views[model.get('id')];
        } else {
            view = new TB_BB.RequestItemView({model : model});
            outerthis.views[model.get('id')] = view;

        }
    });
    $('#request-list').append(els);
    sortingView.render();
    return this;
}

So this works in so much as the views are re-used - however what I have noticed is that if I use a cached view (e.g. the collection has been sorted and the render function finds a cached view) that all of the events on the sub itemview stop working? why is that?

Also could anyone suggest a better way of doing this?

2

2 Answers

3
votes

You can use delegateEvents ( http://documentcloud.github.com/backbone/#View-delegateEvents ) to bind the events again.

0
votes

As OlliM mentioned the reason is because the events are bound to the dom element, but instead of rebinding the element you can also just detach them instead of removing them (detach keeps the event bindings http://api.jquery.com/detach/)

something like

 var $sortContainer = $('#sorting-container');
 $('li', $sortContainer).detach();

And then just reattach the element

 $cnt.append(view.el);

I would also consider using a document fragment while rebuilding/sorting the list and then attaching appending that instead.