Autor Tema: JavaScript HTMLCollection vs NodeList querySelectorAll no funciona? CU01138E#  (Leído 4130 veces)

bermartinv

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 298
    • Ver Perfil
Hola chicos, adjunto codigo que veo más cómodo que el que hace un tiempo adjuntaron nuestros compañeros.

Código: [Seleccionar]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>
#cuadrado{
    position:absolute;
    width:204px;
    height:204px;
    border:solid thin red;
    top:30%;
    left:30%;
    }
div.cuadrante{
    border:solid thin red;
    text-align: center;
    width:100px;
    height:100px;
    float:left;
    line-height: 100px;
   
}
input{
    float:right;
    margin-top:2em;
}

</style>
</head>
<body>
    <div id="cuadrado">
        <div class="cuadrante">
            <span>?</span>                                                                                     
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>       
        <div class="cuadrante">
            <span>?</span>
        </div>
        <input type="button" onclick="avanzar()" value="Avanzar">
    </div>
</body>
<script>
var contador=0;
var cuadrante=document.querySelectorAll(".cuadrante");
function avanzar(){
 
   
    switch (contador){
        case 0: cuadrante[contador].style.backgroundColor="black";
                cuadrante[contador].style.color="white";
                cuadrante[contador].innerHTML="El";
            break;
        case 1:
                cuadrante[contador].innerHTML="poder ";
            break;
        case 2:
                cuadrante[contador].innerHTML="de";
            break;
        case 3: cuadrante[contador].style.backgroundColor="yellow";
                cuadrante[contador].innerHTML="JavaScript";
            break;
        default: alert ("No es posible hacer mas ");
    }
    contador++;
   
}
</script>
</html>
« Última modificación: 09 de Mayo 2021, 20:54 por Ogramar »

Ogramar

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2660
    • Ver Perfil
Buenas bermartinv el código está bien planteado y resuelve lo que pedía el ejercicio a la perfección.

Recomendarte que los scripts con las funciones los incluyas dentro de las etiquetas <head> ... </head> y no en otros lugares para tener mejor organizado el código.

En el código que has propuesto si trasladamos el código de lugar no funciona ¿Por qué? Porque si declaramos var cuadrante=document.querySelectorAll(".cuadrante"); antes de que se haya cargado la página, al hacer la selección no obtenemos nada (ya que no hay nada porque todavía no ha cargado la página). Esto se puede resolver de varias maneras, una de ellas sería utilizar el evento onload y obtener cuadrante después del evento onload, una vez ya existan los elementos con class cuadrante.

Otra opción es meter la creación de cuadrante dentro de la función, como esta función es respuesta a un botón, cuando el usuario pulse el botón ya se habrá cargado la página. Aquí tenemos la pequeña ineficiencia de estar haciendo la selección cada vez que se pulse el botón pero en este ejercicio esto no tiene demasiada importancia. El código sería:

Código: [Seleccionar]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ejercicios aprenderaprogramar.com</title>
<style>
#cuadrado{
    position:absolute;
    width:204px;
    height:204px;
    border:solid thin red;
    top:30%;
    left:30%;
    }
div.cuadrante{
    border:solid thin red;
    text-align: center;
    width:100px;
    height:100px;
    float:left;
    line-height: 100px;
   
}
input{
    float:right;
    margin-top:2em;
}

</style>
<script>
var contador=0;

function avanzar(){
var cuadrante=document.querySelectorAll(".cuadrante");
    switch (contador){
        case 0: cuadrante[contador].style.backgroundColor="black";
                cuadrante[contador].style.color="white";
                cuadrante[contador].innerHTML="El";
            break;
        case 1:
                cuadrante[contador].innerHTML="poder ";
            break;
        case 2:
                cuadrante[contador].innerHTML="de";
            break;
        case 3: cuadrante[contador].style.backgroundColor="yellow";
                cuadrante[contador].innerHTML="JavaScript";
            break;
        default: alert ("No es posible hacer mas ");
    }
    contador++;
   
}
</script>
</head>
<body>
    <div id="cuadrado">
        <div class="cuadrante">
            <span>?</span>                                                                                     
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>       
        <div class="cuadrante">
            <span>?</span>
        </div>
        <input type="button" onclick="avanzar()" value="Avanzar">
    </div>
</body>
</html>

Si lo resuelves con onload te quedará mejor porque solo tendrás que cargar cuadrante una vez.

Salu2

bermartinv

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 298
    • Ver Perfil
Gracias Ogramar, por tu respuesta.

He intentado hacer lo de onload pero no me ha convencido, porque tal como está el código al hacer <body onload="nombre de la funcion">  ya se inicializa la función.

Entonces he decidido cambiar querySelectorAll(".cuadrante") por un getElementsByClass("cuadrante") y cambiar el script dentro de head.

Código: [Seleccionar]
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
<style>
#cuadrado{
    position:absolute;
    width:204px;
    height:204px;
    border:solid thin red;
    top:30%;
    left:30%;
    }
div.cuadrante{
    border:solid thin red;
    text-align: center;
    width:100px;
    height:100px;
    float:left;
    line-height: 100px;
   
}
input{
    float:right;
    margin-top:2em;
}

</style>
<script>
var contador=0;
var cuadrante=document.getElementsByClassName("cuadrante");
function avanzar(){
 
   
    switch (contador){
        case 0: cuadrante[contador].style.backgroundColor="black";
                cuadrante[contador].style.color="white";
                cuadrante[contador].innerHTML="El";
            break;
        case 1:
                cuadrante[contador].innerHTML="poder ";
            break;
        case 2:
                cuadrante[contador].innerHTML="de";
            break;
        case 3: cuadrante[contador].style.backgroundColor="yellow";
                cuadrante[contador].innerHTML="JavaScript";
            break;
        default: alert ("No es posible hacer mas ");
    }
    contador++;
   
}
</script>
</head>
<body>
    <div id="cuadrado">
        <div class="cuadrante">
            <span>?</span>                                                                                     
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>
        <div class="cuadrante">
            <span>?</span>
        </div>       
        <div class="cuadrante">
            <span>?</span>
        </div>
        <input type="button" onclick="avanzar()" value="Avanzar">
    </div>

</body>

</html>
Gracias por tus sugerencias
« Última modificación: 04 de Febrero 2016, 13:00 por Alex Rodríguez »

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2050
    • Ver Perfil
Hola hay algo interesante en el código que se está estudiando y por qué en unos casos funciona y en otros no ¿Por qué querySelectorAll no funciona? Esto está relacionado con la diferencia entre HTMLCollection y NodeList

document.querySelectorAll(".cuadrante") devuelve un object HTMLCollection, esto significa que este método devuelve una lista estática donde los cambios que tengan lugar a posteriori de su inicialización no se reflejan. En este caso en el momento de la inicialización no había nodos, de ahí que la lista estática esté vacía y el método no funcione.

document.getElementsByClassName("cuadrante") devuelve un object NodeList vivo, esto es, una lista dinámica de nodos donde se referencia a los elementos incluyendo los cambios que puedan existir en ellos durante la ejecución. En este caso en el momento de la inicialización no había nodos, pero luego son creados y la referencia dinámica permite acceder a estos elementos cuando se invoca la función.

Aclaración terminológica: a veces se habla de NodeList vivos o dinámicos frente a NodeList no-vivos o estáticos. En ocasiones hay métodos que devuelven NodeList no-vivos (estáticos), por ejemplo document.querySelectorAll se diría que devuelve un NodeList no-vivo o estático. Es un tanto confuso y depende de la referencia que miremos, la cuestión es tener clara la diferencia entre dinámico y estático.

Saludos
« Última modificación: 09 de Febrero 2016, 08:43 por Ogramar »

bermartinv

  • Avanzado
  • ****
  • APR2.COM
  • Mensajes: 298
    • Ver Perfil
Con eso último que has explicado se entiende mucho mejor.
Muchas gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".