How to reverse the position of a div(and its content and attributes) with another div?

Asked

Viewed 5,183 times

6

I wish to do this with jQuery, which is the most elegant way to do it?

Assuming the following scenario, how would it look if I wanted to switch from position to div2 to div3? (I will not post my real code which is too big)

<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>
  • Who just arrived, ignore the downvotes and take a look at mine reply to see a method that exchanges elements independently of the structure.

  • I can’t believe no one’s even suggested classic solution...

6 answers

8


Simplified method:

One way to reconnect the intended operation, with little code but limited to elements that lie next to each other, is to make use of the jQuery method .before(), where what’s done is take the $ele2 and pass the same to before the $ele1:

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

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

See example in Jsfiddle.

We can also use the jQuery method .after() which will do the opposite:

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

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

See example in Jsfiddle.

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


Generic method:

A way to accomplish the intended can be achieved by making use of jQuery method .clone() and the method .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);
}

Utilizing:

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

switchElements($ele1, $ele2);

See example in Jsfiddle.

  • "Simplified" does not work. Try reversing the #div2 with the #div4.

  • 1

    @Guilhermebernal No, it does not work that way, so I was careful to leave note that this method only makes "exchange" when the elements are side by side. That’s why I didn’t suggest it in the first place. To exchange elements "far away" from each other, we need to use the "generic method". : ) see Jsfiddle.

4

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

swap = a
a = b
b = swap

In case Uery would be like this:

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

Clarifying:

  1. a.after(swap) puts swap shortly after a, returning to herself;

  2. a.detach() removes itself from the GIFT - but keeping data and listeners:

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

Full example in jsFiddle.

3

Note

My initial response was simplistic and did not work in 100% of cases. I then made a rather complex implementation, but I have not yet been satisfied, as well as the other answers.

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

Analysis of the proposed solutions

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

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

My answer seems very complex. Does it take all that?

The test of performance

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 discreetly faster than the others when the elements are at the same level, but due to the complexity and excessive use of the jQuery API, when they are at different DOM levels, the performance was equivalent.

Not yet satisfied, I have come to the conclusion that the @mgibsonbr could be easily converted to pure Javascript. I ran the test again and it seems I finally found something interesting.

Let’s see the result in the chart below:

Desempenho de algoritmos de swap

The legend is as follows:

  • Dark blue: my algorithm with nodes of the same level
  • Red: my algorithm with nodes of different levels
  • Yellow: the original algorithm of @mgibsonbr with us of the same level
  • Dark green: the original algorithm of @mgibsonbr with nodes of different levels
  • Purple: the modified algorithm of @mgibsonbr with us of the same level
  • Light blue: the modified algorithm of @mgibsonbr with nodes of different levels
  • Pink: the algorithm of @Zuul with us of the same level
  • Light green: the algorithm of @Zuul with nodes of different levels

Testing in 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));

Mode of Use

$(elementSelector).swap(anotherElementSelector);
  • Well, I created this general-purpose function that attaches to jQuery and switches two elements into any kind of structure. Please evaluate and critique.

3

This is a function that can reverse any sibling elements 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);
    }
}

http://jsfiddle.net/342LP/

  • 1

    @Guilherme Your edition made me think... http://meta.answall.com/questions/249

2

If elements are neighboring, use insertBefore:

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

Example

Executable example: http://jsfiddle.net/rodrigorgs/uya47/

Explanation

To jQuery documentation clarifies:

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

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

If an item selected in this way is inserted in a single location in the FOD, it will be moved to the target (and 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 wrote @utluiz, you can also use the insertAfter; in this case, the order of the items shall be reversed.

  • It didn’t work. Try reversing the #div1 with the #div4.

  • You’re right, I hadn’t thought of the general case =/

1

Try this:

function alterPosition(idElement1, idElement2){
    var div = $(idElement1).clone();
    $(idElement1).remove();
    $(idElement2).before(div);
}
  • Preppend does not insert before of the element?

  • The correct is . before(), . prepend() adds before all the contents of the selected tag...thanks for the remark...

  • 2

    I may be misreading your function, but it seems to me that you are removing the first element, and then you go to the second element and enter before it the first element... I mean, everything stays the same, there was no change of position! :( (Jsfiddle)

  • I think you really misunderstood, I delete the current, and insert it before the desired element, according to the parameter....

  • @Kennyrafael Yes, but in the Fiddle with your code, the div do not change position, see the link I left in the comment. (I might have something wrong with Fiddle, if so, say!)

  • Invert the parameters! ;P

  • And then it worked?

  • Be at least humble enough to take out the votedown...

  • @Kennyrafael I did a quick test but it didn’t work. Now regarding the voteNegative, I’m sorry but it wasn’t me... you can access my profile to confirm that I have not voted negative to anyone!

  • @Kennyrafael To make sure a certain user reads the answer you posted in a comment, use @nomeDoUtilizador, so that he is notified that he has an unread response ;)

  • @Zuul Ok then, but before you question someone else’s answer, make sure you do the tests correctly, because my code works, it may not be ideal, but it works and it’s how I would do before I know other options, you don’t need to speak ill of others' code to promote your response.

  • @Kennyrafael Is this a little strange, it seems that by alerting you to a detail regarding your code I became an "enemy"? I was just trying to help, I even took the trouble to make a Fiddle with your code to check what might be wrong and rectify. I was also careful to say that I might have misread the issue, but other people voted in the comment saying that they agreed with what was said. I honestly don’t understand why you’re so "on your back" about all this.

  • To think that I’m "promoting my response" through this attempt to help, really makes me a little sad! In the future I will refrain from commenting or alerting you to the content of your questions or answers! Positive/negative criticism does not seem to suit you well! :(

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.