DEV Community

Ulises A.F.C
Ulises A.F.C

Posted on • Edited on

Manejo del DOM #4: traversing, creando elementos, fragmentos y templates.

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>

Enter fullscreen mode Exit fullscreen mode

En un archivo .js accederemos a un elemento en concreto:

const $cards = document.querySelector(".cards")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

.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)
Enter fullscreen mode Exit fullscreen mode

.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])
Enter fullscreen mode Exit fullscreen mode

.firstElementChild

Nos devuelve el primer elemento "hijo" del elemento de referencia.

console.log($cards.firstElementChild)
Enter fullscreen mode Exit fullscreen mode

.lastElementChild

Nos devuelve el ultimo elemento "hijo" del elemento de referencia.

console.log($cards.lastElementChild)
Enter fullscreen mode Exit fullscreen mode

.parentElement

Nos devuelve el elemento "padre" del elemento de referencia:

console.log($cards.parentElement)
Enter fullscreen mode Exit fullscreen mode

.previousElementSibling

Nos devuelve el elemento "hermano anterior" del elemento de referencia:

console.log($cards.previousElementSibling)
Enter fullscreen mode Exit fullscreen mode

.nextElementSibling

Nos devuelve el elemento "hermano siguiente" del elemento de referencia:

console.log($cards.nextElementSibling)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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"

Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

.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")

Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

.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)

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

Y también con la etiqueta figcaption para asignarsela como elemento hijo al elemento figure:

// insertando elemento FIGCAPTION a elemento FIGURE
$figure.appendChild($figcaption)

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

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>`

Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

Por ultimo, nos queda insertarlo en el documento HTML, lo incrustaremos en el contenedor de donde se encuentran todas nuestras card.

$cards.appendChild($figureDos)

Enter fullscreen mode Exit fullscreen mode

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>

Enter fullscreen mode Exit fullscreen mode

Seleccionamos ese div desde JavaScript:

const $divmeses = document.getElementById("meses")

Enter fullscreen mode Exit fullscreen mode

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"]

Enter fullscreen mode Exit fullscreen mode

Vamos a crear una lista ul:

const $ul = document.createElement("ul")

Enter fullscreen mode Exit fullscreen mode

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>`
})

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Luego crearemos un array con las estaciones del año:

const estaciones = ["verano", "invierno", "primavera", "otoño"]

Enter fullscreen mode Exit fullscreen mode

Ahora crearemos un fragment con .createDocumentFragment():

const $fragment = document.createDocumentFragment()

Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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)
})
Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

Ahora ya tenemos la lista creada, solo falta insertarlo al div donde lo queremos mostrar:

$divestaciones.appendChild($ulEst)

Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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"
    }
]
Enter fullscreen mode Exit fullscreen mode

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")

Enter fullscreen mode Exit fullscreen mode

Tambien accederemos al "template" de la siguiente manera:

const $templateCard = document.getElementById("template-card").content

Enter fullscreen mode Exit fullscreen mode

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()

Enter fullscreen mode Exit fullscreen mode

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)
})
Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)