Question

Let's say I have the following html structure:

<ul>
  <li>1</li>
  <li>2</li>
  <li>4</li>
</ul>

Is it possible (and how) to insert a new element <li>3</li> in the correct order without detaching the elements and resorting? Reason being, I believe if you .detach() and .append() the elements, you will cause a page reflow (which I suppose would happen anyways if the elements move around). But for some reason, it seems much cleaner to insert it in the right spot vs append/detach/sort/append.

I've seen the nth-child selector in jQuery and I'm working with the underscore.js framework too (which provides _.sortedIndex which tells me the correct position of the element), but I can't seem to figure out the right way to put it in there.

Some background: I'm working with backbone.js and I have a collection of items. Then I assume I need a View of the collection (or view per item in the collection?). When I add an element to the collection, I have the comparator set so the collection is sorted properly, but the View on the page is not sorted.

For those getting here via google, here's what I eventually came up with in backbone.js:

Item = Backbone.Model.extend({});

ItemList = Backbone.Collection.extend({
    model: Item,

    comparator: function(item) {
        return item.get('id');
    }
});

ItemView = Backbone.View.extend({
    tagName: 'li',
    className: 'item',

    initialize: function() {
        _.bindAll(this, 'render');
        this.model.bind('change', this.render);
        this.model.view = this;
    },

    render: function() {
        $(this.el).text(this.model.get('name'));
        return this;
    }
});

App = Backbone.View.extend({
    el: $('#mylist'),

    initialize: function() {
        _.bindAll(this, 'add_one', 'add_all', 'render');

        this.items = new ItemList();
        this.items.bind('add', this.add_one);
        this.items.bind('refresh', this.add_all);
        this.items.bind('all', this.render);

        this.items.add(new Item({id: 2, name: 'two'}));
        this.items.add(new Item({id: 5, name: 'five'}));
        this.items.add(new Item({id: 1, name: 'one'}));
        this.items.add(new Item({id: 4, name: 'four'}));
        this.items.add(new Item({id: 3, name: 'three'}));        
        this.items.add(new Item({id: 6, name: 'six'}));
        this.items.add(new Item({id: 5.5, name: 'five.five'}));
    },

    add_one: function(item) {
        var view = new ItemView({model: item});
        var visible = this.$(view.tagName+'.'+view.className);
        var newel = view.render().el;
        var idx = this.items.indexOf(item);
        if (visible.length == idx) {
            $(this.el).append(newel);
        }
        else {
            visible.eq(idx).before(newel);
        }
    },

    add_all: function() {
        this.items.each(this.add_one);
    }
});

app = new App();

Run it here: http://jsfiddle.net/dlamotte/L4j3b/

Was it helpful?

Solution

you can use a jQuery

$('li').eq(1).after('<li>3</li>');

fiddle page: http://jsfiddle.net/Hrjks/

Better yet:

var myindex = 3;
var insertPoint = myindex -2;
$('li').eq(insertPoint).after('<li>' + myindex +'</li>');

fiddle for this:http://jsfiddle.net/Hrjks/1/

OTHER TIPS

I had the same problem recently and I fixed with the following function.

function sortInsert(parent, element, fnc) {
    var stack = parent.children().filter(function() {
        return fnc($(this), element) > 0;
    });       
    if (stack.length == 0) {
        parent.append(element);
    } else {
        stack.first().before(element);
    }
}

sortInsert($('ul'), $('<li>1</li>'), function(e, a) { 
    return parseInt(e.html()) - parseInt(a.html()); 
} );​

It is basically getting all the child of parent, then doing a filter. If you only need to compare its values you can do it simple by avoiding the callback but in my case it was needed as I was sorting by several criteria.

If you want to sort with a descending order just replace append by prepend, before by last and first for last and it should be working.

Feel free to play in my playground: http://jsfiddle.net/crodas/FMEkb/5/

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