jQuery insert div as certain index
JqueryJquery Problem Overview
Say I have this:
<div id="controller">
<div id="first">1</div>
<div id="second>2</div>
</div>
but say I wanted to insert a new div arbitrarily based on an index I supply.
Say I gave the index to insert of 0, the result should be:
<div id="controller">
<div id="new">new</div>
<div id="first">1</div>
<div id="second">2</div>
</div>
and if I have an index to insert of 2 the result would be.
<div id="controller">
<div id="first">1</div>
<div id="second">2</div>
<div id="new">new</div>
</div>
and if I give an index of 1 the result would be:
<div id="controller">
<div id="first">1</div>
<div id="new">new</div>
<div id="second">2</div>
</div>
just forget that last example's format. The simple act of copying and pasting HTML code on this site is horrific enough to make me about scream and pull my hair out and I dont want to spend anymore time messing with it!
Jquery Solutions
Solution 1 - Jquery
As a function with a little better handling of 0:
function insertAtIndex(i) {
if(i === 0) {
$("#controller").prepend("<div>okay things</div>");
return;
}
$("#controller > div:nth-child(" + (i) + ")").after("<div>great things</div>");
}
EDIT: Added parenthesis in the nth-child selector to avoid NaN errors. @hofnarwillie
function insertAtIndex(i) {
if(i === 0) {
$("#controller").prepend("<div>okay things</div>");
return;
}
$("#controller > div:nth-child(" + (i) + ")").after("<div>great things</div>");
}
window.doInsert = function(){
insertAtIndex(2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="controller">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 4</div>
<div>Item 5</div>
</div>
<button onclick="doInsert()">Insert "great things" at index 2.</button>
Solution 2 - Jquery
I had a similar problem. Unfortunately none of the solutions worked for me. So I coded it this way:
jQuery.fn.insertAt = function(index, element) {
var lastIndex = this.children().size();
if (index < 0) {
index = Math.max(0, lastIndex + 1 + index);
}
this.append(element);
if (index < lastIndex) {
this.children().eq(index).before(this.children().last());
}
return this;
}
Examples for the problem:
$("#controller").insertAt(0, "<div>first insert</div>");
$("#controller").insertAt(-1, "<div>append</div>");
$("#controller").insertAt(1, "<div>insert at second position</div>");
Here are some examples taken from my unittests:
$("<ul/>").insertAt(0, "<li>0</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(1, "<li>1</li>");
$("<ul/>").insertAt(-1, "<li>-1</li>");
$("<ul/>").insertAt(-1, "<li>-1</li>").insertAt(0, "<li>0</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(-1, "<li>-1</li>");
$("<ul/>").insertAt(-1, "<li>-1</li>").insertAt(1, "<li>1</li>");
$("<ul/>").insertAt(-1, "<li>-1</li>").insertAt(99, "<li>99</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(2, "<li>2</li>").insertAt(1, "<li>1</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(1, "<li>1</li>").insertAt(-1, "<li>-1</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(1, "<li>1</li>").insertAt(-2, "<li>-2</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(1, "<li>1</li>").insertAt(-3, "<li>-3</li>");
$("<ul/>").insertAt(0, "<li>0</li>").insertAt(1, "<li>1</li>").insertAt(-99, "<li>-99</li>");
Edit: It handles all negative indizes gracefully now.
Solution 3 - Jquery
I found the listed solutions didn't work or were overly complicated. All you have to do is determine the direction you're appending from. Here is something simple written in an OOP manner for jQuery.
$.fn.insertIndex = function (i) {
// The element we want to swap with
var $target = this.parent().children().eq(i);
// Determine the direction of the appended index so we know what side to place it on
if (this.index() > i) {
$target.before(this);
} else {
$target.after(this);
}
return this;
};
You can simply use the above with some simple syntax.
$('#myListItem').insertIndex(2);
Currently using this on a visual editor project moving tons of data around via drag and drop. Everything is working great.
Edit: I've added a live interactive CodePen demo where you can play with the above solution http://codepen.io/ashblue/full/ktwbe
Solution 4 - Jquery
Use my simple plugin Append With Index
:
$.fn.appendToWithIndex=function(to,index){
if(! to instanceof jQuery){
to=$(to);
};
if(index===0){
$(this).prependTo(to)
}else{
$(this).insertAfter(to.children().eq(index-1));
}
};*
Now :
$('<li>fgdf</li>').appendToWithIndex($('ul'),4)
Or :
$('<li>fgdf</li>').appendToWithIndex('ul',0)
Solution 5 - Jquery
//jQuery plugin insertAtIndex included at bottom of post
//usage:
$('#controller').insertAtIndex(index,'<div id="new">new</div>');
//original:
<div id="controller">
<div id="first">1</div>
<div id="second>2</div>
</div>
//example: use 0 or -int
$('#controller').insertAtIndex(0,'<div id="new">new</div>');
<div id="controller">
<div id="new">new</div>
<div id="first">1</div>
<div id="second>2</div>
</div>
//example: insert at any index
$('#controller').insertAtIndex(1,'<div id="new">new</div>');
<div id="controller">
<div id="first">1</div>
<div id="new">new</div>
<div id="second>2</div>
</div>
//example: handles out of range index by appending
$('#controller').insertAtIndex(2,'<div id="new">new</div>');
<div id="controller">
<div id="first">1</div>
<div id="second>2</div>
<div id="new">new</div>
</div>
/**!
* jQuery insertAtIndex
* project-site: https://github.com/oberlinkwebdev/jQuery.insertAtIndex
* @author: Jesse Oberlin
* @version 1.0
* Copyright 2012, Jesse Oberlin
* Dual licensed under the MIT or GPL Version 2 licenses.
*/
(function ($) {
$.fn.insertAtIndex = function(index,selector){
var opts = $.extend({
index: 0,
selector: '<div/>'
}, {index: index, selector: selector});
return this.each(function() {
var p = $(this);
var i = ($.isNumeric(opts.index) ? parseInt(opts.index) : 0);
if(i <= 0)
p.prepend(opts.selector);
else if( i > p.children().length-1 )
p.append(opts.selector);
else
p.children().eq(i).before(opts.selector);
});
};
})( jQuery );
Solution 6 - Jquery
Use .insertAfter():
$('<div class="new">').insertAfter($('div.first'));
Solution 7 - Jquery
If you need to do this a lot, you can wrap it in a little function:
var addit = function(n){
$('#controller').append('<div id="temp">AAA</div>')
.stop()
.children('div:eq('+n+')')
.before( $('#temp') );
}
addit(2); // adds a new div at position 2 (zero-indexed)
addit(10); // new div always last if n greater than number of divs
addit(0); // new div is the only div if there are no child divs
If you're concerned about that temporary ID, you can add a final step to remove it.
Edit: Updated to handle cases of zero children, and specified n > current number of divs.
Solution 8 - Jquery
This one works best for me,
function SetElementIndex(element, index) {
var Children = $(element).parent().children();
var target = Children[index];
if ($(element).index() > index) {
if (target == null) {
target = Children[0];
}
if (target != element && target != null) {
$(target).before(element);
}
} else {
if (target == null) {
target = Children[Children.length - 1];
}
if (target != element && target != null) {
$(target).after(element);
}
}
};
Solution 9 - Jquery
You could always use prepend('#div');
ex.
$(document).ready(function(){
$('#first').prepend('<div id="new">New</div>');
});
That would put "#new" before "#first" Not sure if that's what you want.