jQuery / Méthode / .replaceWith() - Remplacer des éléments entiers

Dans jQuery, .replaceWith(nouveauContenu) remplace les éléments sélectionnés eux-mêmes. Sa valeur de retour est l’objet jQuery des anciens éléments retirés, et non des nouveaux. Pour manipuler les nouveaux éléments ensuite, conservez une référence séparée ou sélectionnez-les à nouveau dans le document.

Élément entier ou contenu intérieur

.replaceWith() retire les nœuds existants et leurs enfants du modèle objet du document (DOM), puis insère le nouveau contenu à leur place. $(".entry").replaceWith("<section>New</section>") remplace la balise extérieure, les classes et les enfants de .entry. La nouvelle section ne reçoit pas automatiquement la classe .entry.

Utilisez .html() pour conserver l’élément extérieur et changer son contenu. replaceWith accepte une chaîne HTML, un élément DOM, un tableau d’éléments, un objet jQuery ou une fonction renvoyant le contenu de remplacement. Dans cette fonction, this permet de lire chaque ancien élément et de transférer explicitement les valeurs nécessaires.

Exemple complet avec valeurs éditées et événements

Enregistrez tout le code en UTF-8 dans replace-demo.html et ouvrez-le dans le navigateur. Internet est nécessaire pour le fichier jQuery officiel 4.0.0 du réseau de diffusion de contenu (CDN), sans installation. Remplacement, saisie, événements, réinitialisation et extraits de console ont été exécutés avec 3.7.1 et 4.0.0.

Deux div.entry deviennent des section.entry. Les noms sont transférés par .text() et les valeurs actuelles des champs par .val(). Les boutons initiaux ont un gestionnaire direct ; un autre gestionnaire est délégué depuis #board, qui reste en place.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Replace whole elements</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
    button, input { font: inherit; margin: 4px; max-width: 100%; box-sizing: border-box; }
    .entry { padding: 12px; border: 1px solid #aab; margin: 10px 0; }
    section.entry { border: 2px solid teal; background: #edf9f6; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <h1>Replace the outer element</h1>
  <button type="button" id="replace">Replace both entries</button>
  <button type="button" id="reset">Reset</button>
  <div id="board">
    <div class="entry"><strong class="name">Alpha</strong><input aria-label="Alpha note" value="First note"><button type="button" class="inspect">Inspect</button></div>
    <div class="entry"><strong class="name">Beta</strong><input aria-label="Beta note" value="Second note"><button type="button" class="inspect">Inspect</button></div>
  </div>
  <pre id="result" aria-live="polite"></pre>
  <script>
    $(function () {
      const initial = $("#board").html();
      let $old, $returned = null, direct = 0, delegated = 0;
      function report() {
        const tags = $("#board > .entry").map(function () { return this.tagName.toLowerCase(); }).get();
        const connected = $old.filter(function () { return this.isConnected; }).length;
        $("#result").text(`live tags=${tags.join(",")}\noriginal connected=${connected}\nreturned original=${$returned ? $returned === $old : "(not run)"}\nold data=${$old.first().data("lesson")}\ndirect=${direct}; delegated=${delegated}`);
      }
      function initialize() {
        $old = $("#board > .entry").data("lesson", "original");
        $old.find(".inspect").on("click.directExample", function () { direct++; });
        $returned = null; direct = 0; delegated = 0;
        $("#replace").prop("disabled", false);
        report();
      }
      $("#board").on("click.replaceLesson", ".inspect", function () { delegated++; report(); });
      $("#replace").on("click", function () {
        $returned = $old.replaceWith(function () {
          const name = $(this).find(".name").text();
          const note = $(this).find("input").val();
          return $("<section>", { "class": "entry" }).append(
            $("<strong>", { "class": "name" }).text(name),
            $("<input>", { "aria-label": name + " note" }).val(note),
            $("<button>", { type: "button", "class": "inspect" }).text("Inspect")
          );
        });
        $returned.addClass("old-only");
        $(this).prop("disabled", true);
        report();
      });
      $("#reset").on("click", function () { $("#board").html(initial); initialize(); });
      initialize();
    });
  </script>
</body>
</html>

Voici le résultat initial. original connected compte les éléments initiaux toujours reliés au document ; old data indique les données jQuery stockées dessus.

live tags=div,div
original connected=2
returned original=(not run)
old data=original
direct=0; delegated=0
  1. Avant remplacement, appuyez une fois sur Inspect : direct=1; delegated=1. Les deux gestionnaires s’exécutent.
  2. Modifiez le champ Alpha puis appuyez sur Replace both entries. live tags devient section,section ; original connected devient 0 ; returned original vaut true ; old data vaut undefined. La saisie reste grâce à sa copie explicite vers le nouvel input.
  3. Après remplacement, Inspect augmente seulement delegated. Le nouveau bouton est un autre nœud et n’hérite pas du gestionnaire direct.
  4. $returned.addClass("old-only") ajoute une classe aux nœuds retirés. Les nouvelles sections du document ne la reçoivent pas. Vérifiez la différence dans les outils de développement.
  5. Le bouton de remplacement se désactive après une utilisation. Reset restaure HTML, valeurs et compteurs et réinscrit les gestionnaires directs. La délégation est inscrite une seule fois sur #board, sans doublons lors de réinitialisations répétées.

Ne supposez pas que valeurs, données et focus sont transférés automatiquement. L’exemple copie la valeur actuelle, sans restaurer le focus. Pour permettre de poursuivre une saisie, conservez le nouveau contrôle et prévoyez séparément le déplacement de focus nécessaire.

Valeurs de retour et déplacement d’un nœud existant

Gardez le nouvel objet jQuery dans $new avant de le passer à replaceWith. Exécutez ce code dans la console de la même page. Il crée puis supprime des conteneurs temporaires sans modifier les deux cartes principales. .replaceAll() écrit l’opération du nouveau contenu vers les cibles et renvoie l’ensemble inséré.

const $holder = $('<div><p class="slot">A</p><p class="slot">B</p></div>').appendTo("body");
const $new = $("<section>").text("New");
const $removed = $holder.find(".slot").first().replaceWith($new);
console.log(`removed=${$removed.get(0).tagName.toLowerCase()}; new=${$new.get(0).tagName.toLowerCase()}`);
const $inserted = $("<section>").text("Another").replaceAll($holder.find(".slot"));
console.log(`replaceAll inserted=${$inserted.get(0).tagName.toLowerCase()}; live sections=${$holder.children("section").length}`);
$holder.remove();
removed=p; new=section
replaceAll inserted=section; live sections=2

Passer un nœud déjà dans le document pour remplacer une cible unique le déplace depuis son ancien emplacement. Aucune copie supplémentaire ne reste derrière. L’extrait suivant compare l’identité du nœud et confirme qu’un nœud détaché sans parent n’est pas remplacé.

const $holder = $('<div><p class="slot">Placeholder</p><button type="button" class="source">Existing button</button></div>').appendTo("body");
const $source = $holder.find(".source");
const node = $source.get(0);
$holder.find(".slot").replaceWith($source);
console.log(`children=${$holder.children().length}; same node=${$holder.children().get(0) === node}`);
const $orphan = $("<p>Detached without parent</p>");
$orphan.replaceWith("<section>Replacement</section>");
console.log(`orphan tag=${$orphan.get(0).tagName.toLowerCase()}; connected=${$orphan.get(0).isConnected}`);
$holder.remove();
children=1; same node=true
orphan tag=p; connected=false

Réutiliser la même chaîne HTML contenant un id pour plusieurs cibles produit des identifiants en double. Utilisez des classes pour la présentation commune et des id uniques si nécessaire. Ne généralisez pas le déplacement vers une seule cible aux règles de copie et de déplacement sur plusieurs cibles. Si chaque cible doit recevoir un nouveau nœud, créez-le séparément dans une fonction.

Gestionnaires disparus et modifications invisibles

replaceWith nettoie les données jQuery et les gestionnaires des nœuds retirés et de leurs descendants. Il ne copie pas les anciens .on() vers les nouveaux nœuds. Pour des enfants régulièrement remplacés, utilisez la délégation avec .on() sur un ancêtre conservé ou initialisez les nouveaux nœuds. Ce nettoyage ne garantit pas celui de tous les états externes ou écouteurs natifs addEventListener.

Enchaîner .css() ou .addClass() sur l’ancienne sélection peut modifier des nœuds hors du document. Utilisez la nouvelle référence ou une nouvelle sélection limitée. Vérifiez aussi la sélection vide et l’absence de parent : une valeur de retour ne prouve pas à elle seule que le document a changé.

Ne concaténez pas directement une saisie utilisateur au HTML accepté par ces méthodes. L’exemple crée des balises fixes et transmet les noms par .text(), les champs par .val() : <em> n’est donc pas interprété comme une balise. Cela traite ces contextes de texte et de valeur de champ, pas la purification de HTML arbitraire.