web-dev-qa-db-fra.com

Existe-t-il une fonction native jQuery permettant de changer d'éléments?

Puis-je facilement échanger deux éléments avec jQuery?

Je cherche à faire cela avec une ligne si possible.

J'ai un élément select et j'ai deux boutons pour monter ou descendre des options, et j'ai déjà les sélecteurs select et destination en place, je le fais avec un if, mais je me demandais s'il existait un moyen plus simple.

163
juan

J'ai trouvé un moyen intéressant de résoudre ce problème en utilisant uniquement jQuery:

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

ou 

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

:)

216
lotif

Paulo a raison, mais je ne sais pas pourquoi il clone les éléments concernés. Ce n'est pas vraiment nécessaire et perdra toutes les références ou les écouteurs d'événements associés aux éléments et à leurs descendants.

Voici une version sans clonage utilisant des méthodes DOM simples (jQuery n'ayant pas vraiment de fonctions spéciales pour faciliter cette opération particulière):

function swapNodes(a, b) {
    var aparent = a.parentNode;
    var asibling = a.nextSibling === b ? a : a.nextSibling;
    b.parentNode.insertBefore(a, b);
    aparent.insertBefore(b, asibling);
}
75
bobince

Non, il n'y en a pas, mais vous pouvez en préparer un:

jQuery.fn.swapWith = function(to) {
    return this.each(function() {
        var copy_to = $(to).clone(true);
        var copy_from = $(this).clone(true);
        $(to).replaceWith(copy_from);
        $(this).replaceWith(copy_to);
    });
};

Usage:

$(selector1).swapWith(selector2);

Notez que cela ne fonctionne que si les sélecteurs ne correspondent qu'à 1 élément, sinon cela pourrait donner des résultats étranges.

65
Paolo Bergantino

Il y a beaucoup de cas Edge à ce problème, qui ne sont pas traités par la réponse acceptée ou la réponse de bobince. D'autres solutions impliquant le clonage sont sur la bonne voie, mais le clonage est coûteux et inutile. Nous sommes tentés de cloner, en raison du problème séculaire de la permutation de deux variables, l'une des étapes consistant à affecter l'une des variables à une variable temporaire. L'affectation (clonage), dans ce cas, n'est pas nécessaire. Voici une solution basée sur jQuery:

function swap(a, b) {
    a = $(a); b = $(b);
    var tmp = $('<span>').hide();
    a.before(tmp);
    b.before(a);
    tmp.replaceWith(b);
};
35
user2820356

Beaucoup de ces réponses sont tout simplement fausses pour le cas général, d'autres sont inutilement compliquées si elles fonctionnent même. Les méthodes jQuery .before et .after font la plupart de ce que vous voulez faire, mais vous avez besoin d'un 3ème élément similaire au fonctionnement de nombreux algorithmes d'échange. C'est assez simple: créez un élément temporaire du DOM comme espace réservé pendant que vous déplacez des éléments. Il n'est pas nécessaire de regarder les parents ou les frères et sœurs, et certainement pas besoin de cloner ...

$.fn.swapWith = function(that) {
  var $this = this;
  var $that = $(that);

  // create temporary placeholder
  var $temp = $("<div>");

  // 3-step swap
  $this.before($temp);
  $that.before($this);
  $temp.after($that).remove();

  return $this;
}

1) mettre la division temporaire temp avant this 

2) déplacez this avant that

3) déplacez that après temp

3b) supprimer temp

Alors simplement

$(selectorA).swapWith(selectorB);

DEMO: http://codepen.io/anon/pen/akYajE

13
robisrob

Vous ne devriez pas avoir besoin de deux clones, on fera l'affaire. En répondant à Paolo Bergantino, nous avons:

jQuery.fn.swapWith = function(to) {
    return this.each(function() {
        var copy_to = $(to).clone(true);
        $(to).replaceWith(this);
        $(this).replaceWith(copy_to);
    });
};

Devrait être plus rapide. Passer dans le plus petit des deux éléments devrait également accélérer les choses.

11
Matthew Wilcoxson

J'ai utilisé une technique comme celle avant. Je l'utilise pour la liste de connecteurs sur http://mybackupbox.com

// clone element1 and put the clone before element2
$('element1').clone().before('element2').end();

// replace the original element1 with element2
// leaving the element1 clone in it's place
$('element1').replaceWith('element2');
7
Eric Warnke

un autre sans clonage:

J'ai un élément réel et un élément nominal à échanger:

            $nominal.before('<div />')
            $nb=$nominal.prev()
            $nominal.insertAfter($actual)
            $actual.insertAfter($nb)
            $nb.remove()

alors insert <div> before et la remove après ne sont nécessaires que si vous ne pouvez pas vous assurer qu'il y a toujours un élément avant (dans mon cas, c'est le cas)

3
halfbit

J'ai créé une fonction qui vous permet de déplacer plusieurs options sélectionnées vers le haut ou le bas

$('#your_select_box').move_selected_options('down');
$('#your_select_boxt').move_selected_options('up');

Les dépendances:

$.fn.reverse = [].reverse;
function swapWith() (Paolo Bergantino)

Il vérifie d’abord si la première/la dernière option sélectionnée est capable de monter/descendre .

swapWith (element.next () ou element.prev ())

jQuery.fn.move_selected_options = function(up_or_down) {
  if(up_or_down == 'up'){
      var first_can_move_up = $("#" + this.attr('id') + ' option:selected:first').prev().size();
      if(first_can_move_up){
          $.each($("#" + this.attr('id') + ' option:selected'), function(index, option){
              $(option).swapWith($(option).prev());
          });
      }
  } else {
      var last_can_move_down = $("#" + this.attr('id') + ' option:selected:last').next().size();
      if(last_can_move_down){
        $.each($("#" + this.attr('id') + ' option:selected').reverse(), function(index, option){
            $(option).swapWith($(option).next());
        });
      }
  }
  return $(this);
}
3
Tom Maeckelberghe

Voici ma solution pour déplacer plusieurs éléments enfants de haut en bas à l'intérieur de l'élément parent . Fonctionne bien pour déplacer les options sélectionnées dans la liste déroulante (<select multiple></select>)

Déplacer vers le haut:

$(parent).find("childrenSelector").each((idx, child) => {
    $(child).insertBefore($(child).prev().not("childrenSelector"));
});

Descendre:

$($(parent).find("childrenSelector").get().reverse()).each((idx, child) => {
    $(opt).insertAfter($(child).next().not("childrenSelector"));
});
2
pistipanko

jetez un oeil au plugin jQuery "Swapable"

http://code.google.com/p/jquery-swapable/

il est construit sur "Triable" et ressemble à un triable (glisser-déposer, espace réservé, etc.) mais n'échange que deux éléments: glissé-déposé Tous les autres éléments ne sont pas affectés et restent sur leur position actuelle. 

2
vadimk

Ceci est une réponse basée sur la logique de réponse de @lotif, mais un peu plus généralisée

Si vous ajoutez/prepend après/avant les éléments sont réellement déplacés
=> aucun clonage nécessaire
=> événements tenus 

Il y a deux cas qui peuvent arriver

  1. Une cible a quelque chose ".prev() ious" => on peut mettre l'autre cible .after() that.
  2. Une cible est le premier enfant de sa .parent() => on peut .prepend() l'autre cible au parent.

Le code

Ce code pourrait être encore plus court, mais je l’ai gardé ainsi pour plus de lisibilité. Notez que le pré-stockage des parents (si nécessaire) et les éléments précédents sont obligatoires.

$(function(){
  var $one = $("#one");
  var $two = $("#two");

  var $onePrev = $one.prev(); 
  if( $onePrev.length < 1 ) var $oneParent = $one.parent();

  var $twoPrev = $two.prev();
  if( $twoPrev.length < 1 ) var $twoParent = $two.parent();

  if( $onePrev.length > 0 ) $onePrev.after( $two );
    else $oneParent.prepend( $two );

  if( $twoPrev.length > 0 ) $twoPrev.after( $one );
    else $twoParent.prepend( $one );

});

... n'hésitez pas à envelopper le code interne dans une fonction :)

L'exemple de violon a des événements de clic supplémentaires attachés pour démontrer la préservation d'événement ...
Exemple de violon:https://jsfiddle.net/ewroodqa/

... fonctionnera pour différents cas - même un comme:

<div>
  <div id="one">ONE</div>
</div>
<div>Something in the middle</div>
<div>
  <div></div>
  <div id="two">TWO</div>
</div>
2
jave.web

J'ai fait une table pour changer l'ordre des obj dans la base de données utilisée .after () .before (), c'est donc ce que j'ai expérimenté.

$(obj1).after($(obj2))

Est-ce que insérer obj1 avant obj2 et

$(obj1).before($(obj2)) 

faire l'inverse.

Donc si obj1 est après obj3 et obj2 après obj4, et si vous voulez changer de lieu obj1 et obj2 vous le ferez comme

$(obj1).before($(obj4))
$(obj2).before($(obj3))

Cela devrait le faire. BTW vous pouvez utiliser .prev () et .next () pour trouver obj3 et obj4 si vous n’aviez pas déjà une sorte d’index.

1
Tran Vu Dang Khoa

Si vous avez plusieurs copies de chaque élément, vous devez naturellement faire quelque chose dans une boucle. J'ai eu cette situation récemment. Les deux éléments récurrents que je devais basculer avaient des classes et un conteneur div en tant que tel:

<div class="container">
  <span class="item1">xxx</span>
  <span class="item2">yyy</span>
</div> 
and repeat...

Le code suivant m'a permis de parcourir tout et d'inverser ...

$( ".container " ).each(function() {
  $(this).children(".item2").after($(this).children(".item1"));
});
1
AdamJones

Je l'ai fait avec cet extrait

// Create comments
var t1 = $('<!-- -->');
var t2 = $('<!-- -->');
// Position comments next to elements
$(ui.draggable).before(t1);
$(this).before(t2);
// Move elements
t1.after($(this));
t2.after($(ui.draggable));
// Remove comments
t1.remove();
t2.remove();
1
zveljkovic

Je voulais une solution qui n'utilise pas clone () car elle a un effet secondaire avec les événements attachés.

jQuery.fn.swapWith = function(target) {
    if (target.prev().is(this)) {
        target.insertBefore(this);
        return;
    }
    if (target.next().is(this)) {
        target.insertAfter(this);
        return
    }

    var this_to, this_to_obj,
        target_to, target_to_obj;

    if (target.prev().length == 0) {
        this_to = 'before';
        this_to_obj = target.next();
    }
    else {
        this_to = 'after';
        this_to_obj = target.prev();
    }
    if (jQuery(this).prev().length == 0) {
        target_to = 'before';
        target_to_obj = jQuery(this).next();
    }
    else {
        target_to = 'after';
        target_to_obj = jQuery(this).prev();
    }

    if (target_to == 'after') {
        target.insertAfter(target_to_obj);
    }
    else {
        target.insertBefore(target_to_obj);
    }
    if (this_to == 'after') {
        jQuery(this).insertAfter(this_to_obj);
    }
    else {
        jQuery(this).insertBefore(this_to_obj);
    }

    return this;
};

il ne doit pas être utilisé avec des objets jQuery contenant plus d'un élément DOM

1
Mistic

Si vous souhaitez échanger deux éléments sélectionnés dans l'objet jQuery, vous pouvez utiliser cette méthode. 

http://www.vertstudios.com/blog/swap-jquery-plugin/

1
Joseph McCullough

si nodeA et nodeB sont frères, aime deux <tr> dans le même <tbody>, vous pouvez simplement utiliser $(trA).insertAfter($(trB)) ou $(trA).insertBefore($(trB)) pour les échanger, cela fonctionne pour moi. et vous n'avez pas besoin d'appeler $(trA).remove() auparavant, sinon vous devez relier certains événements de clic sur $(trA)

0
Spark.Bao