jQuery / Método / .detach() - Retirar elementos y conservarlos para reutilizarlos
En jQuery, .detach() retira los elementos seleccionados del modelo de objetos del documento, DOM, conservando sus datos y eventos jQuery. Guarda el objeto jQuery devuelto o una referencia existente en una variable para insertarlos después. No es almacenamiento permanente en el navegador ni en un servidor.
Elegir entre detach, remove y empty
.detach() resulta adecuado para retirar temporalmente el mismo elemento y reutilizarlo. El elemento y sus hijos salen juntos; una referencia permite volver a insertarlos. A diferencia de ocultar con CSS, ya no están en el documento y una nueva selección sobre él no los encuentra.
| Método | Qué se retira del documento | Datos/eventos jQuery de partes retiradas | Uso habitual |
|---|---|---|---|
| .detach() | Elementos seleccionados y contenido | Conservados | Separación temporal y reutilización |
| .remove() | Elementos seleccionados y contenido | Limpiados | Descartar elementos |
| .empty() | Hijos y texto de los seleccionados | Limpiados en los hijos retirados | Vaciar manteniendo el contenedor |
.remove() no destruye necesariamente al instante un objeto nodo aún referenciado por una variable JavaScript. Reinsertarlo no restaura automáticamente los datos y eventos jQuery limpiados. .empty() mantiene el contenedor. No elijas solo por el resultado visual compartido de desaparecer.
Ejemplo completo que conserva entrada y eventos
Guarda todo el código en UTF-8 como detach-demo.html y ábrelo en el navegador. Hace falta internet para cargar el archivo oficial de jQuery 4.0.0 desde su red de distribución de contenidos, CDN, sin instalar paquetes. Conservación de entrada, mismo nodo y posición, separación/reinicio repetidos y comparaciones Console se ejecutaron con 3.7.1 y 4.0.0.
Un nodo de comentario anterior a la tarjeta marca su posición. Permanece al separarla y permite que Restore la devuelva a su lugar. La tarjeta guarda count mediante .data() y su botón hijo tiene un manejador directo.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Detach and restore an editable card</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%; }
.card { border: 2px solid teal; padding: 16px; margin: 12px 0; }
</style>
</head>
<body>
<h1>Detach and restore a card</h1>
<button type="button" id="detach">Detach</button>
<button type="button" id="restore">Restore</button>
<button type="button" id="reset">Reset</button>
<div id="slot">
<p>Before the card</p>
<p id="after">After the card</p>
</div>
<p id="result" aria-live="polite"></p>
<script>
$(function () {
const anchor = document.createComment("card position");
$("#after").before(anchor);
let $saved = null;
function makeCard() {
const $card = $('<section class="card"><label>Note <input value="Keep me"></label><p>Count: <span class="count">0</span></p><button type="button" class="increment">Increment</button></section>');
$card.data("count", 0);
$card.find(".increment").on("click", function () {
const count = $card.data("count") + 1;
$card.data("count", count).find(".count").text(count);
report();
});
return $card;
}
let $card = makeCard().insertAfter(anchor);
function report() {
const attached = document.contains($card[0]);
$("#result").text(`attached=${attached} | saved=${$saved !== null} | count=${$card.data("count")}`);
}
$("#detach").on("click", function () {
if ($saved !== null) return;
$saved = $card.detach();
report();
});
$("#restore").on("click", function () {
if ($saved === null) return;
$saved.insertAfter(anchor);
$saved = null;
report();
});
$("#reset").on("click", function () {
$card.remove();
$saved = null;
$card = makeCard().insertAfter(anchor);
report();
});
report();
});
</script>
</body>
</html>
Inicialmente la tarjeta está en el documento y no se conserva aparte como separada:
attached=true | saved=false | count=0
- Cambia Note a Edited note y pulsa una vez Increment en la tarjeta. Count pasa a 1.
- Pulsa Detach. La tarjeta desaparece y muestra
attached=false | saved=true | count=1. Los datos permanecen, pero una nueva consulta de .card en el documento encuentra cero elementos. - Restore la devuelve entre Before y After, conservando Edited note y Count 1.
- Increment eleva Count a 2, confirmando que se conserva el manejador del hijo.
- Repetir Detach o Restore no pierde ni duplica la tarjeta porque el código comprueba el estado guardado.
- Reset funciona también mientras está separada. Limpia la tarjeta vieja con .remove() y crea otra con Keep me y Count 0.
Mantener el valor actual del mismo nodo difiere de crear uno con una nueva cadena HTML. Restore reinserta el nodo guardado; Reset crea otro intencionadamente. Cada tarjeta nueva recibe un manejador una vez, de modo que repetir Reset no multiplica incrementos por clic.
Comparar datos y eventos con remove
Ejecuta este fragmento completo en Console de las herramientas de desarrollo. Crea dos botones en un contenedor temporal, separa uno, elimina otro con remove y vuelve a insertar ambos. La última línea limpia el contenedor de prueba.
const $host = $("<div>").appendTo("body");
let keptClicks = 0;
let removedClicks = 0;
const $keep = $("<button>Keep</button>").data("token", "kept")
.on("click", () => keptClicks++).appendTo($host);
const $gone = $("<button>Remove</button>").data("token", "gone")
.on("click", () => removedClicks++).appendTo($host);
const originalNode = $keep[0];
const $saved = $keep.detach();
console.log(`detached=${!document.contains($saved[0])} | data=${$saved.data("token")}`);
$saved.appendTo($host).trigger("click");
const $removed = $gone.remove();
$removed.appendTo($host).trigger("click");
console.log(`same node=${$saved[0] === originalNode} | kept clicks=${keptClicks}`);
console.log(`removed data=${typeof $removed.data("token")} | removed clicks=${removedClicks}`);
$host.remove();
detached=true | data=kept
same node=true | kept clicks=1
removed data=undefined | removed clicks=0
El botón separado es el mismo nodo y mantiene token y su manejador: kept clicks es 1. El eliminado también puede insertarse mediante su referencia, pero sus datos jQuery son undefined y su manejador directo se limpió: removed clicks es 0. La comparación trata de datos y eventos gestionados por jQuery; no implica limpieza de temporizadores externos o estados de otras bibliotecas.
Filtro de selector y precauciones al restaurar
El selector de .detach(selector) filtra miembros del conjunto ya seleccionado. No busca nuevos hijos dentro de ellos. Este ejemplo Console selecciona A y B, pero separa solo B con .take, por lo que queda A. Las dos últimas líneas limpian los nodos referenciados y el contenedor temporal.
const $list = $('<div><p class="keep">A</p><p class="take">B</p></div>').appendTo("body");
const $items = $list.children("p");
$items.detach(".take");
console.log(`remaining=${$list.children("p").text()}`);
$items.remove();
$list.remove();
remaining=A
Una nueva consulta $(".card") tras separar no recupera la tarjeta. Usa la referencia guardada y gestiona aparte su posición anterior, por ejemplo con el comentario. .appendTo() inserta al final del destino y no recuerda posiciones. Un destino mueve el nodo existente; varios pueden crear copias, por lo que hay que comprobar su número.
Un evento delegado mediante .on() en el padre depende de que el evento se propague por él. Mover el elemento a otro contenedor no transporta los manejadores delegados de su padre anterior. El ejemplo usa un manejador directo en el botón hijo para evidenciar la conservación.
Si no se restaura, revisa que la variable no se haya sobrescrito y que el marcador o destino siga en el documento. Las referencias duraderas mantienen accesibles los objetos separados. Cuando termine la reutilización, limpia el estado jQuery con .remove() y libera las referencias. Cancela temporizadores y suscripciones externas con sus API respectivas.




