How to invert the position of a div (and its contents and attributes) with another div?

6

I want to do this with jQuery, what is the most elegant way to do this?

Assuming the following scenario, what would happen if I wanted to change position to div2 with div3? (I will not post my actual code that is too large)

<body>
    <div id="div1" class="parte1" style="color:black">
        <p> Conteúdo da Div </p>
    </div>
    <div id="div2" class="parte2" style="color:blue">
        <p> Conteúdo da Div </p>
    </div>
    <div id="div3" class="parte3" style="color:red">
        <p> Conteúdo da Div </p>
    </div>
    <div id="div4" class="parte4" style="color:green">
        <p> Conteúdo da Div </p>
    </div>
 </body>
    
asked by anonymous 19.12.2013 / 18:40

6 answers

8

Simplified method:

One way to render the intended operation, with little code but limited to elements that lie side by side, is to use the jQuery method > before () , where what is done is to get the $ele2 and pass the same to before $ele1 :

function switchElements($ele1, $ele2) {
    $ele1.before($ele2);
}

switchElements($('#div2'), $('#div3'));

See example in JSFiddle .

We can also use the .after () jQuery method that will do the inverse:

function switchElements($ele1, $ele2) {
    $ele2.after($ele1);
}

switchElements($('#div2'), $('#div3'));

See example in JSFiddle .

Note:
This is all jQuery methods very similar to those already suggested in other answers. On the other hand it is limited by the fact that the sense of "switching position" is only taken if the elements are side by side.

Generic method:

A way to accomplish what you want can be achieved by using the jQuery .clone () method and .replaceWith () :

// cache elements
var $div1 = $('#div1'),
    $div2 = $('#div2');

// clone elements and their contents
var $div1Clone = $div1.clone(),
    $div2Clone = $div2.clone();

// switch places
$div1.replaceWith($div2Clone);
$div2.replaceWith($div1Clone);

See example in JSFiddle .

Passing this example to a function:

function switchElements($ele1, $ele2) {

    // clone elements and their contents
    var $ele1Clone = $ele1.clone(),
        $ele2Clone = $ele2.clone();

    // switch places
    $ele1.replaceWith($ele2Clone);
    $ele2.replaceWith($ele1Clone);
}

Usage:

// cache elements
var $ele1 = $('#div2'),
    $ele2 = $('#div3');

switchElements($ele1, $ele2);

See example in JSFiddle .

    
19.12.2013 / 18:54
4

I see many different approaches, but none using the classic algorithm to exchange two value variables:

swap = a
a = b
b = swap

In the case of jQuery it would look like this:

function trocar(a, b) {
    var swap = $("<span/>");
    a.after(swap).detach();
    b.after(a).detach();
    swap.after(b).detach();
}

Clarifying:

  • a.after(swap) puts swap soon after a , returning to itself;
  • a.detach() removes itself from DOM - but keeping data and listeners :

      

    The .detach() method is the same as .remove() , except that .detach() holds all jQuery data associated with the removed elements. This method is useful when the removed elements are reinserted into the DOM at a later time.

  • Full example in jsFiddle.

        
    20.12.2013 / 02:50
    3

    This is a function that makes it possible to invert any elements that are siblings in the DOM without using cloning:

    function inverterPosicoes(el1, el2) {
        el1 = $(el1);
        el2 = $(el2);
        var prev = el1.prev();
        var parent = el1.parent();
    
        // Move o primeiro elemento para a posição do segundo
        el2.after(el1);
    
        // Move o segundo elemento para onde o primeiro estava
        if (prev.length) {
            // Se o primeiro elemento não era o primeiro filho
            prev.after(el2);
        } else {
            // Se o primeiro elemento era o primeiro filho
            parent.prepend(el2);
        }
    }
    

    link

        
    19.12.2013 / 19:43
    3

    Note

    My initial response was simplistic and did not work in 100% of cases. I then made a somewhat complex implementation, but I was still not satisfied, as with the other answers.

    I am only considering the general solutions, that is, they apply to changing any elements at different levels and positions.

    Analysis of the proposed solutions

    The simplest and most direct is @mbigsonbr , but I was left behind because of the creation and insertion of an element unnecessarily.

    The @Zuul response of cloning is also simple and interesting, but it also seems even heavier.

    My answer seems very complex. Is it all necessary?

    The performance test

    I then decided to apply the different techniques and do a performance test. The results confirmed my suspicions:

    • Cloning is too slow
    • My solution was slightly faster than the others when the elements are at the same level, but due to the complexity and overuse of the jQuery API, when they are at different levels of the DOM, performance was equivalent. >

    Still unsatisfied, I came to the conclusion that the @mgibsonbr solution could easily be converted to pure Javascript. I ran the test again and it looks like I finally found something interesting.

    Let's look at the result in the chart below:

    Thecaptionisasfollows:

    • Darkblue:myalgorithmwithpeernodes
    • Red:myalgorithmwithdifferentlevelnodes
    • Yellow:theoriginal@mgibsonbralgorithmwithpeernodes
    • DarkGreen:theoriginal@mgibsonbralgorithmwithdifferentlevelnodes
    • Purple:themodified@mgibsonbralgorithmwithpeernodes
    • Lightblue:themodified@mgibsonbralgorithmwithdifferentlevelnodes
    • Pink:@Zuulalgorithmwithpeernodes
    • Lightgreen:@Zuulalgorithmwithdifferentlevelnodes

    Test on jsperf

    My algorithm

    (function ($) {
    
        $.fn.swap = function(anotherElement) {
    
            var sameParentStrategy = function(one, another) {
                var oneIndex = one.index();
                var anotherIndex = another.index();
                var swapFunction = function(first, second, firstIndex, secondIndex) {
                    if (firstIndex == secondIndex - 1) {
                        first.insertAfter(second);
                    } else {
                        var secondPrevious = second.prev();
                        second.insertAfter(first);
                        first.insertAfter(secondPrevious);
                    }
                }
                if (oneIndex < anotherIndex) {
                    swapFunction(one, another, oneIndex, anotherIndex);
                } else {
                    swapFunction(another, one, anotherIndex, oneIndex);
                }
            };
    
            var differentParentsStrategy = function(one, another) {
                var positionStrategy = function(e) {
                    var previous = e.prev();
                    var next = e.next();
                    var parent = e.parent();
                    if (previous.length > 0) {
                        return function(e) {
                            e.insertAfter(previous);
                        };
                    } else if (next.length > 0) {
                        return function(e) {
                            e.insertBefore(next);
                        };
                    } else {
                        return function(e) {
                            parent.append(e);
                        };
                    }
                }
                var oneStrategy = positionStrategy(one);
                var anotherStrategy = positionStrategy(another);
                oneStrategy(another);
                anotherStrategy(one);
                return this;
            };
    
            //check better strategy
            var one = $(this);
            var another = $(anotherElement);
            if (one.parent().get(0) == another.parent().get(0)) {
                console.log('sameParentStrategy');
                sameParentStrategy(one, another);
            } else {
                console.log('differentParentsStrategy');
                differentParentsStrategy(one, another);
            }
    
        };
    
    }(jQuery));
    

    Demo no jsfiddle .

    The modified algorithm of @mgibsonbr

    (function ($) {
        $.fn.swap = function(anotherElement) {
            var a = $(this).get(0);
            var b = $(anotherElement).get(0);
            var swap = document.createElement('span');
            a.parentNode.insertBefore(swap, a);
            b.parentNode.insertBefore(a, b);
            swap.parentNode.insertBefore(b, swap);
            swap.remove();
        }
    }(jQuery));
    

    How to Use

    $(elementSelector).swap(anotherElementSelector);
    
        
    19.12.2013 / 18:51
    2

    If the elements are neighbors, use insertBefore :

    $('#div3').insertBefore($('#div2'));
    

    Example

    Executable example: link

    Explanation

    The jQuery documentation clarifies:

      

    You can select one page element and insert it before another:

         

    $( "h2" ).insertBefore( $( ".container" ) );

         

    If an element selected in this way is inserted in a single location in the DOM, it will be moved to the target (not cloned).

         

    If there is more than one target element, however, copies of the element will be inserted for each target after the first.

    (free translation)

    As you typed @utluiz , you can also use insertAfter ; in this case, the order of the elements is inverted.

        
    19.12.2013 / 18:49
    1

    Try this:

    function alterPosition(idElement1, idElement2){
        var div = $(idElement1).clone();
        $(idElement1).remove();
        $(idElement2).before(div);
    }
    
        
    19.12.2013 / 18:44