jQuery Inserting elements in the correct order vs detach().sort()?
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 th开发者_开发技巧ose 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/
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/
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/
精彩评论