duduromeroa.com

#Javascript, #DOMJs, #webinteractiva, #Interfaces, #duduromeroa, #Guayaquil

Javascript | DOM | API

Programación para web con Javascript: estudio del Document Object Model (DOM) 2


George Póyla, matemático. Resolver problemas de diseño. www.duduromeroa.com

Por Eduardo J. Romero Andrade
| Guayaquil

Contenido

querySelector(), querySelectorAll(), document.body, document.body.children, childNodes, innerText, getElementsByTagName(), getElementsByClassName





Ya mencionamos que en Javascript y en muchos lenguajes dirigidos a manipular clases son los objetos quienes agrupan métodos -acciones– y propiedades con valores. Por lo que al modificar elementos HTML accederemos a los objetos de la API DOM.

SELECCIONAR ELEMENTOS HTML DESDE EL DOM

Los selectores querySelector() y querySelectorAll son dos métodos comunes para seleccionar elementos HTML a partir de su clase o id.

ESTRUCTURA PARA EJEMPLOS

Si bien el objeto DOM contiene la estructura de los elementos HTML presentes en toda página web, usaré los lenguajes JS y HTML para acceder a esos elementos. Recomiendo conocer el lenguaje HTML al detalle mediante tutoriales o bibliografía técnica en caso de seguir con el estudio del DOM. La base del código es la siguiente:



<!doctype html>
<html>
<head>
<!-- Permite mostrar caracteres tildados -->
<meta charset="UTF-8">

	<script>
	// Aquí el código JS que accede a los elementos HTML
	</script>

</head>
	<body>
	<!-- Aquí los elementos HTML -->
	</body>
</html> 


Selector querySelector()

Apunta a un elemento HTML según su nombre de etiqueta (por ejemplo "h1", "p"), o su id, o class.

RECORDAR

Para apuntar a un elemento HTML según su CLASE o ID sólo es necesario el selector document.querySelector("..."). Lo que sí cambia es el signo de etiqueta: id ("#nombre") o class (".nombre")

.

/* La función querySelector()... */
let variable = document.querySelector( ___ );	

/* Puede apuntar desde su parámetro () a: */
/*... al elemento ID */ 
".identificadorId" 		
/*... al elemento CLASS */ 
"#identificadorClass"
/*... al un elemento HTML */ 	
"h1", "p"...		

Sin embargo, cuando cada uno de estos selectores es conectado con el objeto, entonces se convierten en métodos que devolverán un resultado. Ojo en la sintaxis para apuntar al elemento html: 'document.querySelector ("elemento");'

En HTML

<h1 class="titulo"> Aquí va el titulo </h1>

En Javascript

/* Obtener el primer elemento "h1". 
Se guarda ese puntero en la variable 'elem'  */
	let elem = document.querySelector("h1");

/* En consola se invoca la variable 
que guarda el elemento apuntado */
	console.dir(elem);
// En consola se muestra: h1.titulo

Desde la función console() ambos códigos devolverán dos valores: el nombre de la etiqueta apuntada -'h1'- y el nombre de la clase a la que apunta esa etiqueta: "titulo".

De igual forma, se puede acceder a un elemento HTML que contenga un identificador ID. Ojo en la sintaxis para apuntar al elemento con ID: 'document.querySelector ("#nombreElementoId");'

En HTML

<h3 class="nada"> ... </h3>
	<h3 class="nada"> ... </h3>
	<h3 id="subtitulo"> Elemento ID</h3> 

Javascript

 /* Obtener el elemento con ID. Se aloja lo apuntado 
en una variable */
	let elem = document.querySelector("#subtitulo");
	console.dir(elem);
// En consola: h3#subtitulo

En otro ejemplo seleccionamos los elementos según el nombre identificador id o la clase.

En HTML

<h3 class="cosaClase"> ... </h3>
	<h3 id="cosaIdentificador"> ... </h3>

Javascript

/* Alojamos el elemento de la CLASE apuntada en una variable */ 
let elem = document.querySelector(".cosaClase");
console.dir(elem);
// Consola muestra h3.cosaClase

/* Alojamos el elemento del ID apuntado en una variable */ 
let elem2 = document.querySelector("#cosaIdentificador");
console.dir(elem2);
// Consola muestra:
// h3#cosaIdentificador

RECORDAR

Cada identificador en los querySelector() va agrupado en paréntesis y comillas ("..."). Ejemplo:

  • ...querySelector ("#identificadorClase");
  • ...querySelector (".identificadorId");




Selector querySelectorAll()

Selecciona todos los elementos según el identificador de la clase de esos elementos:

En HTML

<h3 class="titulo"> Aquí va primer titulo </h3>	
<h3 class="titulo"> Aquí va segundo titulo </h3>	
<h3 class="titulo"> Aquí va tercer titulo </h3> 

Javascript

/* Alojar en una variable el conjunto 
de clases que se está apuntando desde 
el identificador "titulo" */
let elem = document.querySelectorAll(".titulo");
/* Invocar la variable */
console.dir(elem);

/* En consola se muestra:
0:h3.titulo
1:h3.titulo
2:h3.titulo
length:3
*/

Hasta aquí nada extraordinario sucede. En HTML se nombran a los elementos como (class="...") o (id="...") y se los apunta mediante document. querySelector(); o document. querySelectorAll(). Por lo tanto, como se demostrará en las siguientes secciones, es a partir de esa selección que podremos alterarlos y manipularlos.

MANIPULAR ELEMENTOS USANDO EL DOM

Manipular elementos HTML desde el DOM significa explorarlos, seleccionarlos, añadirles estilo e interacción junto con nuevos atributos entre otros.

PROPIEDAD BODY

Para Lars Svekis y van Putten [5] la propiedad body contiene todo lo que se halla dentro de los tags <body> ... </body> del documento HTML:

  • Recordar: Siempre que deseemos acceder a los métodos del DOM, debemos iniciar con el objeto document., luego con el método útil para obtener y manipular los elementos del DOM y finalmente con el identidicador del elemento a apuntar.
  • Por ejemplo: document .querySelector("h1");

Javascript

/* Escribiendo en consola */
console.dir(document.body);
/* El Inspector mostrará docenas 
de propiedades y valores del objeto body:
body
aLink:""
accessKey:""
ariaAtomic:null
ariaAutoComplete:null...
*/

/* Otro ejemplo en una variable */
var seleccion = querySelection(document.body);

UBICAR ELEMENTOS HIJO CON LA PROPIEDAD CHILDREN

Obtiene elementos HTML anidados uno dentro de otros. El primer padre es document.body y luego, cada propiedad children apuntará al elemento inmediato (el hijo) de cada padre. Ejemplo:

En HTML

<!-- Padre -->
	<div id="Padre1"> ... 
	<!-- Hijo y padre -->
		<div id="hijo1"> 
	<!-- Hijo y padre -->
		<div id="Padre2">
	<!-- Solo hijos -->
			<div id="Hijo2A">..</div>
			<div id="Hijo2B">..</div>
		</div> 
		</div>
	</div>

Javascript

/* Selecciona SOLO el hijo1 */
console.dir(document.body
.children.Padre1
.children.hijo1);
// -> Muestra en consola: div#hijo1

/* Selecciona SOLO el padre1 */
console.dir(document.body
.children.Padre1);
// -> Muestra en consola: div#Padre1

/* Selecciona SOLO el hijo2A */
console.dir(document.body
.children.Padre1
.children.hijo1
.children.Padre2
.children.Hijo2A);
// -> Muestra en consola: div#Hijo2A
  • La secuencia es: ...body.padre. children.hijo
  • Un elemento padre es cada identificador que agrupa otro elemento.
  • Cada childnode debe inicia con un padre...
  • ...y luego de eso apunta al hijo.
  • Recordar: muchas veces un hijo también es padre de otro elemento.

APUNTAR ELEMENTOS CON LA PROPIEDAD CHILDNODES

Permite en breve determinar un arreglo (array) cuyo índice dado apuntará al elemento HTML a seleccionar.

  • Recordar: para ejecutar estos ejercicios, copia el código HTML en un archivo 'nombre.html'. Luego, abre el archivo en un navegador. Después, ejecuta el modo inspector (en computadores de escritorio es con click derecho + elegir Inspector en el menú). Finalmente, elige la pestaña de 'console' e inserta en esa ventana sólo el código de JS. El resultado se mostrará en una sola línea.

En HTML

<!-- OJO CON ESTO: El espacio de arriba es un nodo [0] #text.
Este comentario es un nodo [1] #comment y el espacio 
siguiente antes del div es otro nodo [2] #text -->
<div id="Padre1"> ... </div>

Javascript

/* Seleccionar Padre1. 
Según los elementos de arriba, el nodo con id 'Padre1' 
corresponde al índice [3] */
console.dir(document.body

// Muestra div#Padre1 pero no muestra el contenido
.childNodes[3]);
//-> Muestra div#Padre1 

//-> Muestra #comment 
.childNodes[1]);
//-> #comment 

Solo en caso de que se eliminen los espacios vacíos y los comentarios, el nodo [0] sería entonces el elemento Padre1.

IMPORTANTE DIFERENCIA

La propiedad childNodes devuelve un objeto nodeList, accedido mediante índice numérico [..]. Este objeto puede ser un espacio de caracter vacio, los comentarios del código o la etiqueta HTML y su clase o Id. En otras palabras, todos esos elementos (los comentarios, las etiquetas HTML y sus clases o IDs) son nodos que apuntan a un índice.


Por otro lado, la propiedad children solo devuelve elementos HTML (no toma en cuenta espacios vacios y comentarios).



Para mostrar el índice de los nodos y su cantidad:

En HTML

<div id="Afuera">
		<div id="dentro"></div>
	</div>	

Javascript

let todoEldiv = document.getElementById("Afuera");
let mostrar = todoEldiv.childNodes;
console.dir(mostrar);
//-> Cantidad de nodos
/* NodeList(3)
0: text
1: div#dentro
2: text
length: 3
[[Prototype]]: NodeList */

Para mostrar las etiquetas y los elementos nodos de un body en tiempo real:

En HTML

<!-- Cada salto de linea es un nodo #text -->
<h1> </h1>
<h2> </h2>
<p> </p>

<p>Los elementos son:</p>
<p id="demo"></p>

Javascript

/* Se aloja en una variable 
todos los nodos hijo presentes 
en el documento abierto en el navegador */
const listaNodos = document.body.childNodes;

// Para guardar todo lo hallado
let loHallado = "";

// Iteración: Recorre todos los nodos mediante indice
for (let i = 0; i < listaNodos.length; i++) {

/* --El atributo nodeName muestra el nombre de cada nodo. 
--loHallado alojará su propio contenido + el recorrido  
de los nodos gracias al atributo nodename */
  loHallado = loHallado + listaNodos[i].nodeName + "
"; } /* Apunta a obtener el contenido interno del id=demo. Ojo con esta igualdad: desde el llamado de un elemento del DOM que tendrá el valor del recorrido de la iteración. */ document.getElementById("demo").innerHTML = loHallado; /* En la pantalla se muestra: Los elementos son: #text, #comment, #text, #comment, #text, H1, #text, H2, #text, P, #text, P, #text, P, #text, SCRIPT */

  • Propiedad '.innerHTML': Añade o remueve el contenido de un elemento HTML que será mostrado en la página del navegador. Ojo: manipular una gran cantidad de nodos con '.innerHTML' podría cargar al navegador.
  • En el ejemplo de abajo (y desde un archivo .html) se agrega y se muestra desde JS un elemento HTML que aún no existe.

  • En HTML

    <body> <!-- Inicialmente aquí no hay nada --> </body>
    

    En Javascript

    /* La propiedad 'createElement' crea un elemento HTML 
    según la etiqueta dada */ 
    var frase = document.createElement("p");
    
    // Pedimos que dentro de 'frase' se inserte "Para envolverte...
    frase.innerHTML = "Para envolverte en besos...";
    
    /* El método appendChild() adjunta o inserta al final 
    de un nodo padre un elemento asignado desde el argumento, 
    y muestra el elemento adjuntado en el navegador. */
    document.body.appendChild(frase);
    
    /* En el navegador se mostrará la frase: 
    Para envolverte en besos quisiera ser el viento */
    
  • OJO: la propiedad 'innerHTML' inserta o adjunta el nodo. Pero el método 'appendChild()' lo muestra en el navegador.

  • Propiedad '.createElement()': Crea un nuevo elemento HTML desde un único argumento. Este argumento es el nombre del elemento HTML: 'div', 'p', etc...

Tener en cuenta algo interesante en el penúltimo ejemplo antes del recuadro celeste: se creó una igualdad desde el llamado de un elemento del DOM y una variable. Similar al ejemplo de abajo: se pide que el llamado a un nodo DOM sea igual (o lo que es lo mismo) que inserte en ese llamado el contenido de la variable. Por lo tanto, en este contexto la igualdad significa 'inserte aquí'.

En HTML

<!-- Elemento id declarado pero vacío de contenido -->
<div id="demo"> </div>

En Javascript

// Aloja string
var myText = "Eres perla que surgiste...";
// Obtiene el contenido interno del id 'demo' = ...
// E inserta el contenido de la variable myText
document.getElementById("demo").innerHTML = myText;

// Se muestra en el Navegador
// 'Eres perla que surgiste...'

INSERTAR ESTILOS CSS A LOS ELEMENTOS HIJOS SEGÚN CHILDNODES[..] y CHILDREN[..], Y MOSTRARLOS

Dos propiedades similares permiten acceder y manipular los elementos hijos a partir de un elemento padre y a partir de un número índice: .childNodes[] y .children[].

.childNodes[] accede en toda la colección o lista de elementos nodos al igual que espacios en blanco y etiquetas; y también a los no-nodos como los textos dentro de las etiquetas y comentarios de código. En este ejemplo, los elementos <p> están ubicados en una sola línea de código. Esto evita confusiones en el conteo de los nodos y no-nodos. Es decir, se los organizó sin espacios de la siguiente forma: <p>texto</p><p>texto</p><p>texto</p>. Por lo tanto, al haber 3 nodos se puede apuntar a uno de los 3 mediante .childNodes[...]. En este caso se apuntó solo al nodo índice 1 -ver el código en consola-.

Nodo índice Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Nodo índice 2 Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam

Nodo índice 3 Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur


Por otro lado, .children[] devuelve únicamente el elemento nodo hijo de un padre. Sin embargo, ¿por qué contamos esta vez desde el índice 0 en adelante? Puesto que .children[] solo apunta a los nodos hijos del padre, solo contaremos los índices desde el cero en adelante. .children[] no lee los no/nodos, como los texto o comentarios. Incluso, de haberlos, solo detectará los nodos o etiquetas de elementos.

Nodo índice 0 Lorem ipsum dolor sit amet

Nodo índice 1 Sed ut perspiciatis unde omnis iste natus error

Nodo índice 2 Nemo enim ipsam voluptatem quia voluptas


Por otro lado, una forma de apuntar a un nodo que anteceda a otro es mediante la propiedad previousElementSibling. Solo a manera de concepto: entre dos elementos A y B, .children[B]. previousElementSibling; apuntará a su elemento anterior (al elemento A). Pero si no está explícito uno de los dos nodos, el mensaje dará un mensaje de 'undefined'.

Nodo 0 Lorem ipsum dolor sit amet

Nodo 1 sed do eiusmod tempor

Nodo 2 Ut enim ad minim veniam

Nodo 3 sed do eiusmod tempor


SELECCIONAR Y CAMBIAR LAS PROPIEDADES DE LOS ELEMENTOS NODO

En HTML

<h1> aaa </h1>
<p id="saludos"> bbb </p>

Javascript

/* Solo apunta a todos los elementos hijos de body, 
tengan o no identificador id o class. Nada nuevo aún. */
document.body.children.saludos;

PROPIEDAD INNERTEXT

Inserta un contenido dado explícito y lo prepara para ser mostrado. En este caso, se usarán dos tags con identificadores id="..." que inicialmente están vacíos. La propiedad 'innerText' les añadió contenido:

.

.


En otro ejemplo se insertará contenido mediante .innerText hacia los hijos del documento <body>

En HTML

<!-- Las etiquetas h1 y p están vacías -->
<body>
<h1 id="saludos"></h1>
<p id="textito"></p>
</body>

Javascript

/* h1 mostrará 'hola' */
document.body.children.saludos.innerText = "hola!!";
/*  p mostrará 'amigos' */
document.body.children.textito.innerText = "amigos";

/* Luego de eso ambas etiquetas mostrarán 
las nuevas palabras en el nevegador */

PROPIEDAD INNERHTML

La propiedad innerHTML obtiene y altera contenido dentro de un elemento HTML -ver código en consola-.

Este texto esta primero


Abajo, otro ejemplo más interactivo en el uso de .innerHtml. Un click al botón ejecuta la acción

Eres perla...


ACCEDER A ELEMENTOS DESDE EL ID

El método getElementById() devuelve un elemento apuntando a un id único –no se repite en ningún lado de ese documento–.

En HTML

<h1> Ejemplo </h1>
<div id="uno" class="ejemplo"> aaa </div>
<div id="dos" class="ejemplo"> bbb </div>
<div id="tres" class="algo"> ccc </div>

Javascript

console.dir( document.getElementById("two") );
//-> div#dos.ejemplo

En el ejemplo de abajo: Se alojará el ID apuntado en una variable creada. Luego se creará otra variable para alojar un nuevo elemento 'h2' en el cual se mostrará el contenido seleccionado. La propiedad .innerText se usará para 'insertar' lo seleccionado dentro del nuevo h2 creado. Finalmente se usará document.querySelector("") para apuntar al contenedor padre donde queremos se ubique el elemento seleccionado. Y se usará .appendChild() para concretar esa inserción. (Revisar código en consola).

Eres perla..
que surgiste..
del más grande e ignoto mar..

Se elije:


  • Usar document. body. appendChild(nodoElegido) hubiera mostrado el nodo elegido 'Eres perla..' al final de esta página web. Ya que se deseaba ubicar el resultado dentro del padre div, se necesitó usar alojar en una variable a document. querySelector(".padre"); y luego, adjuntar el resultado elegido mediante padreVar. appendChild(elegido);.
ACCEDER A ELEMENTOS DESDE EL NOMBRE DEL TAG (tag name)

Propiedad no sensible al nombre de las etiquetas a la que apunta. Es decir, getElementsByTagName ("div") apuntará a ese elemento así sea ("DIV") o ("dIV"). Esa propiedad apuntará a un elemento HTML por su nombre de tag. Sin embargo, podría dar como resultado un tipo de dato arreglo o una lista de nodos (pueden haber más de un elemento con el mismo nombre de tag, como el tag <div>...</div>) como en el siguiente ejemplo:

Javascript con el mismo bloque HTML dado arriba

// Apunta a todos los elementos de tag 'div'
// Ojo con ElementS –termina en 's'-
console.dir(document.getElementsByTagName("div"));

// La consola muestra:
/* HTMLCollection(3)
0: div#uno.ejemplo
1: div#dos.ejemplo
2: div#tres.algo
dos: div#dos.ejemplo
tres: div#tres.algo
uno: div#uno.ejemplo
length: 3 */

Por eso es útil apuntar a elementos ID únicos, y no a nombres de tag (que pueden ser cientos de elementos).

APUNTAR A ELEMENTOS SEGÚN SU TAG Y SU INDICE

Mediante el método getElementsByTagName –OJO, es ElementS– y mediante el métodos item().

Los elementos son:

Gringa loca,
fuiste tú la que se quiso casar,
me llevaste con engaño...

El script resulta en:


En otro ejemplo, se escoge un elemento según el índice:

En HTML

<div id="a" class="letra"> aaa </div>
<div id="b" class="letra"> bbb </div>
<p id="num" class="numero"> 222 </div>
<p id="num1" class="numero"> 333 </div>

Javascript

/* Ubicar el 'div' con indice cero */
console.dir(
document.getElementsByTagName("div").item(0)
);
// -> div#a.letra

/* Ubicar el 'p' con indice cero */
console.dir(document.getElementsByTagName("p").item(1));
// -> p#num1.numero

Para apuntar a un elemento con el ID dado, usar también namedItem(".."). Por ejemplo:

En HTML

<p id="xx" class="numero"> 222 </div>
<p id="yy" class="numero"> 333 </div>

Javascript

/* Ubicar el 'div' con el ID 'num' */
console.dir(
document.getElementsByTagName("p").
namedItem("identificador_ID"));
// p#num.numero

/* Cuando se invoca con console.log(); */
console.log(
document.getElementsByTagName("p").namedItem("xx"));
/* -> <p id="xx" class="numero"> 222 </p> */

Para apuntar a todos los elementos de un mismo tipo (por ejemplo, solo elementos <p>) se usa como argumento de getElementsByTagName("...") el nombre de la etiqueta a apuntar. El resultado será un HTMLCollection de todos los elementos <p> sea cual fuere su ID o su CLASS:

  • ERROR (Omitir la S): getElementByTagName ("...")
  • CORRECTO (Con la S): getElementsByTagName ("...")

En HTML

<!-- Todos son elementos <p>-->

<!--Sin ID o CLASS-->
<p> .. </div>

<!-- Sin CLASS-->
<p id="bb"> .. </div>

<!-- Sin ID-->
<p class="numero"> .. </div>

Javascript

/* Apuntar a todos los elementos <p>*/
console.log(
document.getElementsByTagName("p"));

/* HTMLCollection(3)
0: p#aa.numero
1: p#bb.numero
2: p#cc.numero
aa: p#aa.numero
bb: p#bb.numero
cc: p#cc.numero
len

APUNTAR A ELEMENTOS POR EL NOMBRE DE CLASE (CLASS NAME)

En HTML

<!-- Elementos con igual clase -->
<p class="xx" id="holi"> .. </div>
<p class="xx" id="lali"> .. </div>
<p class="zz"> .. </div>

Javascript

/* Apuntar a elementos de clase 'xx' */
console.log(
document.getElementsByClassName("xx"));

/* -> HTMLCollection(2)
0: p#holi.xx
1: p#lali.xx
holi: p#holi.xx
lali: p#lali.xx
length:2 

* Notar que el elemento 'p' de clase 'zz' no es mostrado. */


BIBLIOGRAFÍA:
    3ra edición. 2018. Marijn Haverbeke. No starch press.
    Mozilla Foundation.
    David Flanagan (2020). Editorial O'Reilly.
    Ved Antani, Stoyan Stefanov (2017). Packt Publishing.
    Editorial Packt.
    Information and Computation. Elsevier.
    ACM SIGCSE BulletinVolume 19Issue 1Feb. 1987 pp 98–102