jQuery insert div as certain index

Jquery

Jquery 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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDantheManView Question on Stackoverflow
Solution 1 - JqueryAndy GaskellView Answer on Stackoverflow
Solution 2 - JqueryBenjamin GudehusView Answer on Stackoverflow
Solution 3 - JqueryAsh BlueView Answer on Stackoverflow
Solution 4 - JqueryAbdennour TOUMIView Answer on Stackoverflow
Solution 5 - JqueryoLinkWebDevelopmentView Answer on Stackoverflow
Solution 6 - JqueryyPhilView Answer on Stackoverflow
Solution 7 - JqueryKen RedlerView Answer on Stackoverflow
Solution 8 - JqueryPhil SnookView Answer on Stackoverflow
Solution 9 - JqueryMoDFoXView Answer on Stackoverflow