jQuery insert div as certain index

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>

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.


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


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)

//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 );