Question

I'm comfortable with the comparator function in Backbone.Collection and I'm also comfortable with the idea of sorting a collection and then redrawing the whole thing from a view. However, I'm not looking for that here.

I've got a collection that has been sorted (upon load). One view listens to the collection and is responsible for iterating through it on "reset". The models of the collection have their own view. Nothing out of the ordinary here.

However, the user is able to edit each model in-line, potentially changing the value of the attribute that is featured in the comparator function. Obviously one solution would be to just clear the whole collection's view, re-sort the collection, and then redraw all the models' views. But I'd like to avoid doing that if possible.

Ideally, I should be able to remove the altered model from the collection's view and then re-insert it at its new, appropriate, position in the collection view (so I'm only doing one DOM removal and one DOM addition - rather than clearing and then redrawing the entire collection of models). I could of course do this manually, without any help from backbone, but I thought I'd ask if there are any features of backbone that could make it easier, or at least more streamlined. Doing this completely outside of backbone seems like a hack, and it won't look pretty.

Was it helpful?

Solution

I think I know what you're getting at. Assuming you have access to the models and views in question, here's a basic approach:

// assumption: this is called on "change" event, only once
re_insert_item : function(model,m_view,collection,c_view) {

    // remove the model's view from the DOM
    m_view.$el.remove();

    // assuming there is a comparator, sort() will move the
    // model into the correct position of the collection. since
    // we're not doing a .remove and .add, we have to sort manually
    // (as per documentation instructions)
    collection.sort();

    // figure out the model that, based upon its sort position, our
    // edited model will come *before*
    var idx = collection.indexOf(model);
    var next_model = collection.at(idx+1);

    // insert our model's view into the DOM right above it's neighbour
    // this assumes you have some way to get a view for a given model,
    // which there isn't really a "standard" way to do (it seems)
    if ( next_model ) {
        var next_m_view = ??? // assume you have some way to get this
        next_m_view.$el.before(m_view.render().$el);
    }

    // this model is last in the list, so just append it to the
    // collection view (assuming the collection view houses the
    // master list as its $el)
    else {
        c_view.$el.append(m_view.render().$el);
    }
}

You'll have to change a bunch of it depending on: a) where you plan to put the code - i.e., where/how you're going to get the function params from; b) how you have your models and views linked together.

There was a (somewhat) similar question asked here on SO. However, in contrast to the answer I highlighted with the above link, I prefer not to use DOM traversal code if I can avoid it, instead relying on the ordering of backbone's collection.

Nevertheless, I think this is what you're looking for. If not, please be as specific as possible regarding what's missing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top