Modificar el DOM con JavaScript
En esta lección
En la lección anterior cambiabas elementos que ya estaban en el HTML. Pero muchas veces el contenido depende de datos: una lista de productos que llega de un servidor, las tareas que añade el usuario, los resultados de una búsqueda. En esos casos hay que crear los elementos con JavaScript.
Los tres pasos
// 1. Crear el elemento
const parrafo = document.createElement("p");
// 2. Rellenarlo: texto, clases, atributos
parrafo.textContent = "Soy un párrafo nuevo";
parrafo.classList.add("aviso");
// 3. Colocarlo en la página
document.querySelector("#contenedor").append(parrafo);
createElement recibe el nombre de cualquier etiqueta ("li", "img", "button", "tr"…). Hasta que no lo colocas con append o similar, el elemento existe en memoria pero no se ve.
Dónde colocarlo
Dado un elemento de referencia, hay cuatro posiciones posibles:
referencia.before(nuevo); // justo ANTES, fuera de la referencia
referencia.prepend(nuevo); // DENTRO, al principio
referencia.append(nuevo); // DENTRO, al final
referencia.after(nuevo); // justo DESPUÉS, fuera de la referencia
[before]
<ul id="referencia">
[prepend]
<li>...</li>
[append]
</ul>
[after]
Los cuatro aceptan varios elementos a la vez y también texto: lista.append(li1, li2, "texto suelto").
(En código antiguo verás appendChild e insertBefore. Hacen lo mismo con una sintaxis más incómoda.)
append frente a textContent
textContent = ...sustituye todo lo que había dentro del elemento, y solo sirve para texto.append(...)añade al final, sin borrar lo que había, y sirve para elementos y texto.
Para vaciar un elemento antes de volver a rellenarlo: lista.replaceChildren() (sin argumentos) o lista.textContent = "".
Reemplazar y borrar
viejo.replaceWith(nuevo); // pone "nuevo" en el sitio de "viejo"
elemento.remove(); // lo quita de la página
Para borrar varios, selecciónalos por una clase y recórrelos:
for (const tarea of document.querySelectorAll(".completada")) {
tarea.remove();
}
Por eso es buena idea añadir una clase a los elementos que creas: luego es fácil encontrarlos todos.
Crear elementos con atributos
Cada atributo HTML es una propiedad del objeto:
const img = document.createElement("img");
img.src = "img/gato.jpg";
img.alt = "Gato atigrado durmiendo en una caja";
img.width = 300;
const enlace = document.createElement("a");
enlace.href = "https://developer.mozilla.org/es/";
enlace.textContent = "MDN";
enlace.target = "_blank";
enlace.rel = "noopener";
Construir contenido a partir de datos
El caso más habitual: tienes un array de objetos y quieres mostrarlos. Crea una función que reciba un dato y devuelva un elemento:
function crearTarjeta(producto) {
const tarjeta = document.createElement("article");
tarjeta.classList.add("tarjeta");
const titulo = document.createElement("h3");
titulo.textContent = producto.nombre;
const precio = document.createElement("p");
precio.textContent = `${producto.precio.toFixed(2)} €`;
tarjeta.append(titulo, precio);
return tarjeta;
}
const productos = [
{ nombre: "Taza", precio: 8 },
{ nombre: "Camiseta", precio: 19.5 },
];
const galeria = document.querySelector("#galeria");
galeria.replaceChildren(...productos.map(crearTarjeta));
Con map conviertes cada producto en una tarjeta, y con replaceChildren(...) las colocas todas de una vez, sustituyendo lo que hubiera.
Una tabla fila a fila
Las tablas se construyen igual: crear la fila, crear cada celda, meter las celdas en la fila y la fila en la tabla.
function agregarFila(tabla, valores) {
const tr = document.createElement("tr");
for (const valor of valores) {
const td = document.createElement("td");
td.textContent = valor;
tr.append(td);
}
tabla.append(tr);
}
agregarFila(document.querySelector("#registro"), [1, new Date().toLocaleTimeString("es-ES")]);
innerHTML con plantillas: cómodo pero con cuidado
Construir mucho HTML elemento a elemento es largo. Con innerHTML y una plantilla de texto es más corto:
galeria.innerHTML = productos
.map((p) => `<article class="tarjeta"><h3>${p.nombre}</h3><p>${p.precio} €</p></article>`)
.join("");
Es aceptable solo si los datos son tuyos. Si alguno viene de un usuario (un comentario, un nombre), podría contener etiquetas <script> o atributos maliciosos que se ejecutarían en tu página (ataque XSS). Con textContent, en cambio, cualquier texto se muestra tal cual, sin interpretarse. Ante la duda, usa createElement y textContent.
<template>: moldes en el HTML
Si la estructura es grande, puedes escribirla en el HTML dentro de un <template>, que el navegador no muestra, y clonarla desde JavaScript:
<template id="molde-tarea">
<li class="tarea">
<input type="checkbox">
<span class="texto"></span>
<button class="borrar" aria-label="Borrar tarea">✕</button>
</li>
</template>
const molde = document.querySelector("#molde-tarea");
function crearTarea(texto) {
const copia = molde.content.cloneNode(true);
copia.querySelector(".texto").textContent = texto;
return copia;
}
document.querySelector("#tareas").append(crearTarea("Estudiar el DOM"));
Así el HTML queda en el HTML y el JavaScript solo rellena los huecos.
Generar contenido al cargar la página
No todo tiene que ocurrir al pulsar un botón. Si llamas a tus funciones directamente en el script, se ejecutan al cargar la página:
function pintarProductos() { /* ... */ }
pintarProductos(); // se ejecuta al cargar
Un detalle importante: si una imagen o un elemento va a rellenarse con JavaScript, rellénalo al cargar con un valor inicial. Una página que al abrirse muestra huecos vacíos o imágenes rotas parece estropeada.
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.