Manejo del DOM #4: traversing, creando elementos, fragmentos y templates.
Tags: webdev, javascript, beginners, programming
Published: 2024-03-14 04:45:19

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