13

What the best way to switch two elements in DOM with jquery?

<div id="switchme2">some other elements in here....</div>
<div class="some other elements"></div>
<div id="switchme1">some other elements in here....</div>

should end in:

<div id="switchme1">some other elements in here....</div>
<div class="some other elements"></div>
<div id="switchme2">some other elements in here....</div>
ggzone
  • 3,661
  • 8
  • 36
  • 59

2 Answers2

34

You'll get people telling you to use jQuery's before, after, and such, but beware, that can mess things up if there are text nodes on either side of either element (more on that below).

Because of that (and for people not using jQuery), you can just use the DOM directly:

function swapElements(elm1, elm2) {
    var parent1, next1,
        parent2, next2;

    parent1 = elm1.parentNode;
    next1   = elm1.nextSibling;
    parent2 = elm2.parentNode;
    next2   = elm2.nextSibling;

    parent1.insertBefore(elm2, next1);
    parent2.insertBefore(elm1, next2);
}

Note that it's fine if the reference element (next1 or next2 above) is null; insertBefore handles that correctly (by adding at the end of the parent, like appendChild would).

Usage combined with jQuery:

swapElements($("#switchme1")[0], $("#switchme2")[0]);

Live example:

jQuery(function($) {
  
    function swapElements(elm1, elm2, elm3, elm4, elm5) {
        var parent1, next1,
            parent2, next2,
            parent3, next3,
            parent4, next4,
            parent5, next5;

        parent1 = elm1.parentNode;
        next1   = elm1.nextSibling;
        parent2 = elm2.parentNode;
        next2   = elm2.nextSibling;
        parent3 = elm3.parentNode;
        next3   = elm3.nextSibling;
        parent4 = elm4.parentNode;
        next4   = elm4.nextSibling;
        parent5 = elm5.parentNode;
        next5   = elm5.nextSibling;

        parent1.insertBefore(elm2, next1);
        parent2.insertBefore(elm3, next2);
        parent3.insertBefore(elm4, next3);
        parent4.insertBefore(elm5, next4);
        parent5.insertBefore(elm1, next5);
    }

    $("#btnSwitch").click(function() {
        swapElements($("#switchme1")[0], $("#switchme2")[0], $("#switchme3")[0], $("#switchme4")[0], $("#switchme5")[0]);
    });
  
});
first text node
<div id="switchme1">this is <strong>switchme1</strong> with <strong>some other elements</strong> <em>in here<div>test</div></em></div>
second text node
<div id="switchme2">this is <strong>switchme2</strong> with <strong>some other elements</strong> <em>in here</em></div>
<div id="switchme3">this is <strong>switchme3</strong> with <strong>some other elements</strong> <em>in here</em></div>
<div id="switchme4">this is <strong>switchme4</strong> with <strong>some other elements</strong> <em>in here</em></div>
<div id="switchme5">this is <strong>switchme5</strong> with <strong>some other elements</strong> <em>in here</em></div>
third text node
<input type="button" id="btnSwitch" value="Switch Em!">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

More about jQuery's before, after, and such: Because jQuery tends to give you access mostly to elements (which is what you want 95% of the time!), if the elements you want to swap have text nodes around them, using those methods will mess things up. (You also have to either remember which one goes in front or figure it out.) In contrast, the swapElements method above above works regardless of whether the elements are surrounded by other elements or text nodes, and you don't have to remember or figure out which should go in front.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • nextSibling may be null: in that case use appendChild instead of insertBefore –  May 27 '13 at 05:57
  • 2
    @Wes: There's no need, `insertBefore` knows what to do if the reference element is `null`. I've added a note to the answer. – T.J. Crowder May 27 '13 at 06:04
  • are you sure this is cross browser? –  May 27 '13 at 06:09
  • @Wes: *"are you sure this is cross browser?"* Yes. It was [specified back in 1998 as part of DOM1](http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-core.html#method-insertBefore) and I know it works in IE6, so... :-) – T.J. Crowder May 27 '13 at 07:05
  • yes but you know... msie is not famous for its standard support :P –  May 27 '13 at 07:38
  • @BennyBottema: Nearly three years, and no one had reported noticing the truly blatant copy-and-paste error. Thank you for letting me know, fixed it. – T.J. Crowder Mar 24 '16 at 20:20
4

See this stack overflow question.

Basically says:

jQuery("#element1").before(jQuery("#element2"));

or

jQuery("#element1").after(jQuery("#element2"));

Beautiful eh? - Credit to lotif.

Community
  • 1
  • 1
David Hobs
  • 4,351
  • 2
  • 21
  • 22
  • 3
    Except that using `before` or `after` will mess things up if the elements being switched have text nodes on either side of them (as I mentioned in my answer back in Nov '11 -- I've just edited to make that clearer). Example of what happens: http://jsbin.com/alozun/13 – T.J. Crowder May 27 '13 at 08:14