Manejo del DOM #4: traversing, creando elementos, fragmentos y templates.
Ulises A.F.C
Posted on March 14, 2024
DOM Traversing
Recorrido del DOM, desde JavaScript podemos recorrer elementos HTML tomando como referencia un nodo en especifico. Podemos acceder a los "hijos" de un elemento "padre", podemos acceder al elemento "padre", saber cuantos elementos "hijos" tiene un elemento en concreto, acceder al primer y ultimo elemento, acceder a elementos hermanos, siempre y cuando tomemos de referencia un nodo para poder recorrer el DOM.
Tomaremos de ejemplo el siguiente código HTML:
<main>
<article>
<input type="search" name="buscar" id="txtsearch">
<a class="linkuser" href="index.html" data-link="inicio de pagina" data-name="enlace home">Ir a</a>
</article>
<section class="cards">
<figure class="card">
<img src="https://picsum.photos/id/237/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
<figure class="card">
<img src="https://picsum.photos/id/23/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
<figure class="card">
<img src="https://picsum.photos/id/137/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
<figure class="card">
<img src="https://picsum.photos/id/267/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
<figure class="card">
<img src="https://picsum.photos/id/27/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
<figure class="card">
<img src="https://picsum.photos/id/239/200/200" alt="card">
<figcaption>Card</figcaption>
</figure>
</section>
<div></div>
</main>
En un archivo .js
accederemos a un elemento en concreto:
const $cards = document.querySelector(".cards")
Veamos cada uno de las propiedades para recorrer elementos:
.childElementCount
Nos devuelve la cantidad de elementos "hijos" del elemento de referencia.
console.log($cards.childElementCount)
.childNodes
Nos devuelve la cantidad de nodos secundarios de un elemento, esta propiedad toma en cuenta los nodos del documento HTML, esto incluye los saltos de línea o espacios en blanco.
console.log($cards.childNodes)
.children[]
Nos devuelve el elemento "hijo" especificando la posición en la que se encuentra, si hay 5 elementos y queremos acceder al elemento "3" especificamos la posición numero #3.
console.log($cards.children[3])
.firstElementChild
Nos devuelve el primer elemento "hijo" del elemento de referencia.
console.log($cards.firstElementChild)
.lastElementChild
Nos devuelve el ultimo elemento "hijo" del elemento de referencia.
console.log($cards.lastElementChild)
.parentElement
Nos devuelve el elemento "padre" del elemento de referencia:
console.log($cards.parentElement)
.previousElementSibling
Nos devuelve el elemento "hermano anterior" del elemento de referencia:
console.log($cards.previousElementSibling)
.nextElementSibling
Nos devuelve el elemento "hermano siguiente" del elemento de referencia:
console.log($cards.nextElementSibling)
De esta manera podemos recorrer elementos del DOM tomando de referencia un elemento en concreto, esto nos permite tener acceso a elementos en específicos para tomarles de referencia y en base a eso insertar elementos adicionales al DOM.
Creando elementos HTML desde JavaScript
Desde JavaScript podemos crear elementos HTML e insertarlos en el documento, hay diferentes formas de hacerlo y veremos cada una de ellas.
Seguiremos tomando de ejemplo el código HTML del ejemplo anterior y crearemos una nueva card
para insertarla junto a las demás.
Primer forma:
Seleccionamos el contenedor de donde se encuentran las card
:
const $cards = document.querySelector(".cards")
Para empezar debemos tomar en cuenta que las card
que hemos creado incluye una etiqueta img
las cuales como atributo indica una dirección URL de una imagen y un nombre alternativo, iniciaremos creando una constante para la dirección URL de la imagen y para el nombre alternativo:
/* ATRIBUTOS IMG */
const SRC = "https://picsum.photos/id/199/200/200"
const ALT = "Card New"
Iniciemos a crear elementos HTML:
.createElement()
Con este metodo podemos crear elementos HTML, toda aquella etiqueta de apertura y cierre HTML. Con ello crearemos la etiqueta figure
, la etiqueta img
y la etiqueta figcaption
para completar una card
adicional al documento:
// creando elementos
const $figure = document.createElement("figure")
const $img = document.createElement("img")
const $figcaption = document.createElement("figcaption")
.createTextNode()
Este método nos permite crear texto en forma que el navegador lo interprete como un nodo de tipo texto. Con este método crearemos el texto que ira dentro de la etiqueta figcaption
con el texto de CARD NEW
indicando que es la nueva card
que estamos creando:
// creando nodo de texto
const $figcaptionText = document.createTextNode("CARD NEW")
Ya tenemos las partes de la card
creadas, solo nos falta unirlas y complementarlas, iniciaremos con la etiqueta img
definiendo sus atributos con las constantes que habíamos creado anteriormente, recordemos que para asignar atributos se utiliza .setAttribute()
:
// definiendo atributos a IMG
$img.setAttribute("src", SRC)
$img.setAttribute("alt", ALT)
.appendChild()
Con este método podemos asignarle un elemento hijo a un elemento padre, en este caso empezaremos a asignarle el nodo de tipo texto como hijo al elemento figcaption
, que vendría siendo el elemento padre:
// insertando nodo de texto a elemento FIGCAPTION
$figcaption.appendChild($figcaptionText)
Haremos lo mismo con la etiqueta img
para asignársela como elemento hijo al elemento figure
:
// insertando elemento IMG a elemento FIGURE
$figure.appendChild($img)
Y también con la etiqueta figcaption
para asignarsela como elemento hijo al elemento figure
:
// insertando elemento FIGCAPTION a elemento FIGURE
$figure.appendChild($figcaption)
Ya tenemos armada la card
con sus elementos hijos, solo nos falta insertarla como elemento hijo al elemento padre que es donde se encuentran todas nuestras card
:
// insertando elemento FIGURE a contenedor .cards
$cards.appendChild($figure)
Hasta acá ya tenemos nuestra card
creada e insertada en el documento HTML donde corresponde, pero falta una cosa, y es asignarle la clase CSS para que tome el mismo estilo que las demás card
:
// definiendo clase CSS a elemento FIGURE
$figure.classList.add("card")
Esta es la forma en la que podemos crear elementos, los métodos .createElement()
& .appendChild()
nos dan accesibilidad a crear elementos y armarlos por partes. Existen otros métodos como el siguiente que veremos a continuación:
Segunda forma:
Continuaremos con otra forma de crear elementos desde JavaScript, crearemos otra card
pero de una forma diferente.
Crearemos un nuevo elemento:
const $figureDos = document.createElement("figure")
Una vez creado nuestro elemento figure
podemos empezar a armar nuestra card
con lo siguiente:
.innerHTML
Esta propiedad nos permite definir código HTML dentro de JavaScript, veamos como:
$figureDos.innerHTML = `
<img src="${SRC}" alt="${ALT}">
<figcaption>CARD NEW</figcaption>`
Con ayuda de template string
que vienen siendo un tipo de comilla para incrustar variables, con la ayuda de ello podemos definir los valores de src
y alt
con las constantes que habíamos creado anteriormente, si puedes observar es código HTML, esto nos permite insertar código HTML en el elemento que creamos.
Como paso siguiente es agregarle la clase CSS al elemento figure
:
$figureDos.classList.add("card")
Por ultimo, nos queda insertarlo en el documento HTML, lo incrustaremos en el contenedor de donde se encuentran todas nuestras card
.
$cards.appendChild($figureDos)
Y ya podemos ver los resultados en el navegador, esta es una manera rápida de hacerlo, es válido hacerlo si solamente es algo pequeño de incrustar HTML en el documento desde JavaScript.
A continuación, veremos otras dos formas de crear elementos desde JavaScript pero de forma dinámica, es decir, si queremos crear varios elementos a partir de mucha información, desde un objeto o un arreglo, veamos los siguiente ejemplos:
Tercera forma
En el documento HTML crearemos un div
con un id
llamado "meses" :
<div id="meses"></div>
Seleccionamos ese div
desde JavaScript:
const $divmeses = document.getElementById("meses")
Crearemos un array
con los meses del año para posteriormente crear una lista de ellos e insertarlos en el documento HTML:
const meses = ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"]
Vamos a crear una lista ul
:
const $ul = document.createElement("ul")
El siguiente paso es recorrer el array
de datos con los meses del año, luego nos apoyaremos de la propiedad .innerHTML
para crear los items de la lista dinámicamente a cada elemento del array
:
meses.forEach(el => {
$ul.innerHTML += `<li>${el}</li>`
})
Por cada elemento recorrido iremos agregando un li
(list item) dentro de nuestra lista ul
, para ello asignamos con +=
para que vaya agregando un elemento tras otro.
Solo nos queda insertar en el documento HTML la lista que hemos creado:
$divmeses.appendChild($ul)
Esta es la tercera forma de crear elementos pero de una forma dinámica en base a varios elementos en común a partir de cierta información, en este caso fue un array
de los meses del año.
Cuarta forma
Continuaremos con la siguiente forma de crear elementos de una forma dinámica, pero a traves de un fragmento
, empezaremos creando un div
en el documento HTML para después insertar los elementos dentro:
<div id="estaciones"></div>
Luego crearemos un array
con las estaciones del año:
const estaciones = ["verano", "invierno", "primavera", "otoño"]
Ahora crearemos un fragment
con .createDocumentFragment():
const $fragment = document.createDocumentFragment()
Este fragmento nos permite adicionar elementos dentro de él, para posteriormente insertarlos al DOM. Se muestran en el DOM hasta que son insertados.
Crearemos una lista:
const $ulEst = document.createElement("ul")
Ahora viene lo interesante del uso de fragment
, recorreremos el array
para crear un li
por cada elemento recorrido:
estaciones.forEach(el => {
const $li = document.createElement("li")
$li.textContent = el
$fragment.appendChild($li)
})
Por cada elemento, creamos un elemento li
y dentro de el por medio de .textContent
le asignamos el valor de cada elemento recorrido, por último, al fragment
le vamos adicionando cada li
que se crea por cada vuelta del bucle.
Ahora dentro del fragment
se encuentra cada li
con cada estación del año, ahora agregaremos este fragmento dentro de la lista:
$ulEst.appendChild($fragment)
Ahora ya tenemos la lista creada, solo falta insertarlo al div
donde lo queremos mostrar:
$divestaciones.appendChild($ulEst)
Y ya podemos ver el resultado en la página, esta es otra manera de crear elementos de forma dinámica utilizando fragmentos, los fragmentos nos permiten adicionar elementos sin que se muestren en el DOM, solamente se muestran o están preparados para mostrarse hasta que se asigna como hijos. Es una forma correcta de hacerlo.
Template HTML y elementos dinámicos
Los "template" HTML se crean con la etiqueta <template></template>
, este es un mecanismo para contener fragmentos HTML que pueden usarse a través de JavaScript o mantenerse oculto en el DOM.
Ya que hemos visto los "fragmentos" ahora veremos como usarlos también implementando los "template" HTML, veamos un ejemplo sencillo generando "cards" dinámicamente a través de un objeto.
Empezaremos creando un template
en el documento HTML y a darle forma de una "card", esta será nuestra plantilla de como queremos mostrar las "card" que crearemos dinámicamente:
<template id="template-card">
<figure class="card">
<img>
<figcaption></figcaption>
</figure>
</template>
Al "template" le pondremos un selector de identificador con el nombre de "template-card" para poder acceder a su contenido desde JavaScript. Dentro tenemos la estructura de una "card" con la clase "card" en donde se le aplicarían los estilos CSS, dentro tenemos la etiqueta "img" y la etiqueta "figcaption".
A través de JavaScript crearemos un array
objetos, donde cada objeto tendrá dos propiedades con una dirección URL de diferentes imágenes y un titulo para el "figcaption":
const data = [
{
src: "https://picsum.photos/id/31/200/200",
title: "ID31"
},
{
src: "https://picsum.photos/id/32/200/200",
title: "ID32"
},
{
src: "https://picsum.photos/id/33/200/200",
title: "ID33"
},
{
src: "https://picsum.photos/id/34/200/200",
title: "ID34"
},
{
src: "https://picsum.photos/id/35/200/200",
title: "ID35"
}
]
Este es el array de objetos llamado "data", con la propiedad llamada "src" con una direccion URL de una imagen la cual le asignaremos como atributo a la etiqueta "img" del "template" que hemos creado, asi mismo para el "figcaption" donde le insertaremos el texto de la propiedad "title" del array de objetos.
Continuaremos seleccionando el contenedor de todas las "card" para luego insertar las demás "card" que iremos creando:
const $cards = document.querySelector(".cards")
Tambien accederemos al "template" de la siguiente manera:
const $templateCard = document.getElementById("template-card").content
Accedemos al "template" pero añadimos .content
para poder acceder a los elementos dentro del "template".
Por ultimo nos falta crear un "fragmento":
const $fragment = document.createDocumentFragment()
Ahora veamos como podemos hacer uso del "fragmento" y del "template" para crear "cards" dinámicas, según este ejemplo:
data.forEach(el => {
$templateCard.querySelector("img").setAttribute("src", el.src)
$templateCard.querySelector("figcaption").textContent = el.title
let clone = document.importNode($templateCard, true)
$fragment.appendChild(clone)
})
Primero, recorreremos el "array" con el método foreach
, luego, por cada elemento que este recorra accederemos al elemento "img" y le asignaremos como atributo la propiedad "src" del array de objetos, así mismo accederemos al elemento "figcaption" para incrustarle el texto de la propiedad "title" del array de objetos.
Dentro del "template" tenemos los elementos "img" y "figcaption" totalmente vacíos, al obtener el "template" desde JavaScript junto con la propiedad
.content
, este nos permite mapear lo que hay dentro de las etiquetas "template" con ayuda de un.querySelector()
. Por medio de eso podemos asignarle los atributos e incrustar el texto a los elementos desde las propiedades del "array de objetos" que creamos.
Una vez hecho esto ahora viene lo interesante, a partir de lo que tenemos hasta el momento, debemos crear "clones", es decir, el "template" nos sirve como plantilla de lo que queremos crear y mostrar, es por eso que por cada vuelta del bucle foreach
vamos a crear "x" cantidad de lo mismo:
let clone = document.importNode($templateCard, true)
$fragment.appendChild(clone)
Por ello definimos una variable llamada "clone" y lo creamos con el método .importNode()
, este recibe 2 parámetros, el primero es de donde sacaremos los clones, el segundo es un valor boolean
, especificamos a true
para indicarle que queremos clonar toda la estructura según como lo hemos indicado, con todo sus elementos, atributos, textos, etc.
Luego de eso, al "fragmento" le añadimos como hijos todos los "clones" que acabamos de definir. Se lo añadimos al "fragmento" ya que no queremos mostrarlos al DOM todavía.
Por ultimo, al salir del bucle ya podemos insertar los elementos creados que se encuentran en el "fragmento" listos para mostrarse en el DOM:
$cards.appendChild($fragment)
Añadimos el "fragmento" dentro del contenedor donde se mostraran cada "card" creada.
Y con esto ya podemos ver el resultado, los "template" nos permiten definir plantillas, y dinámicamente podemos definir datos desde JavaScript para poder insertar elementos al DOM, todo esto con ayuda de "fragmentos", este fue un ejemplo sencillo donde podemos simular un arreglo de datos, así como lo es una petición a una API.
Posted on March 14, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.