JavaScript Ninja Quiz

¿Qué vamos a construir?

Vamos a construir un cuestionario para ver cuál es tu nivel de JavaScript, de 0 a 100 (o ninja ?). Es un proyecto inspirado en cursos como el de JavaScript from novice to ninja. Aquí puedes ver la versión final.

¿Y esto a qué viene?

Después de aprender sobre temas como las callback functions o el DOM, es momento de practicar a fondo. Porque sólo haciendo proyectos es cuando te encuentras con problemas enfocados a la vida real de un programador. ¡Vamos allá! ?

Pre-requisitos y consejos

? Debes tener unas nociones básicas de cómo funciona JavaScript. Pero don't worry, aquí tienes una colección de artículos que tratan temas básicos sobre JavaScript.

? Yo utilizo vsCode como IDE y una extensión llamada live-server para ver los cambios en mi navegador sin necesidad de recargar la página.

Estructura de archivos

Vamos a trabajar con un archivo HTML vinculado a un archivo JS (JavaScript). Los llamaremos index.html app.js respectivamente. Para darle estilazo, vamos a trabajar con Bootstrap 4. Me encanta Bootstrap. Y eso que en su día aprendí muy bien CSS3. Pero Bootstrap me permite construir apps a la velocidad del rayo. ⚡

Bootstrap es una librería CSS y de JS, pero nosotros sólo vamos a utilizar la parte del CSS, porque la parte del JS la vamos a construir desde cero. ?

Para incluir Bootstrap en nuestro proyecto, no tenemos más que incluir su CDN en nuestro index.html.

Este es el esqueleto inicial del index.html con el que arrancamos nuestro proyecto:​​

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <title>Ninja Quiz</title>
</head>
<body>
    <script src="app.js"></script>
</body>
</html>

Subrayado puedes ver el CDN de Bootstrap. 

Definiendo el contenido HTML

Vamos a crear todo el contenido de nuestro index.html con la ayuda de Bootstrap. ​​

1. Construimos una sección superior. Vamos a ir comentando el código para que nos resulte más fácil de reconocer. De hecho, comentar tu código es una buena práctica. ✌

Vamos a usar también nuestras propias clases de CSS.

2. Construimos la sección que abarca todo el cuestionario. Aquí es donde incluiremos un formulario (o form).

Así nos queda el <body> tras aplicarle los pasos 1 y 2:

<!--************************* top section **********************************-->
<div class="intro py-3 bg-white text-center">
    <div class="container">
        <h2 class="text-primary display-4 my-4" id="tab-con-5">JavaScript Ninja Quiz</h2>
    </div>
</div>
<!--************************* quiz section **********************************-->
<div class="quiz py-4 bg-primary">
    <div class="container">
        <h2 class="my-5 text-white" id="tab-con-10">Answer before this page autodestructs! 3, 2, 1... ?</h2>
        <form class="quiz-form text-light">
            <div class="my-5">
                <p class="lead font-weight-normal">
                    1. What's the difference between JavaScript and Java?
                </p>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q1" value="A" checked="">
                    <label class="form-check-label">
                        "Java" is just short for "JavaScript"
                    </label>
                </div>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q1" value="B">
                    <label class="form-check-label">
                        Java is a backend language whereas JavaScript is a frontend language
                    </label>
                </div>
            </div>
            <div class="my-5">
                <p class="lead font-weight-normal">
                    2. How do you solve a coding problem when you are stuck?
                </p>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q2" value="A" checked="">
                    <label class="form-check-label">
                        Stare at the computer during hours and start to think about punching the screen
                    </label>
                </div>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q2" value="B">
                    <label class="form-check-label">
                        Ask your dear friend Google
                    </label>
                </div>
            </div>
            <div class="my-5">
                <p class="lead font-weight-normal">
                    3. What does BOM mean?
                </p>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q3" value="A" checked="">
                    <label class="form-check-label">
                        Browser Object Model
                    </label>
                </div>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q3" value="B">
                    <label class="form-check-label">
                        Board of Managers
                    </label>
                </div>
            </div>
            <div class="my-5">
                <p class="lead font-weight-normal">
                    4. What is FreeCodeCamp?
                </p>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q4" value="A" checked="">
                    <label class="form-check-label">
                        A Scout group of the Rocky Mountains
                    </label>
                </div>
                <div class="form-check my-2 text-white-50">
                    <input type="radio" name="q4" value="B">
                    <label class="form-check-label">
                        An online platform to learn web development
                    </label>
                </div>
            </div>
            <div class="text-center">
                <input type="submit" class="btn btn-light">
            </div>
        </form>
    </div>
</div>
<script src="app.js"></script>

Reaccionando a las respuestas del usuario

Con nuestra HTML template terminada, ahora vamos a capturar las respuestas que el usuario marca en el cuestionario. Por cada respuesta positiva sumaremos 25 puntos, lo que significa que si las acierta todas, obtiene un 100.

Para llevar a cabo esta tarea, nos vamos al archivo app.js.

1. ​​Creamos un array con las respuestas correctas. El valor de la respuesta lo encontramos en el atributo value de cada <input type="radio">. En mi caso, las respuestas correctas para cada una de las cuatro preguntas serían: B, B, A, B. Asegúrate de escribirlas en mayúsculas, porque JS es case sensitive. 

2. Creamos una referencia al formulario y le añadimos un event listener para capturar cuándo un usuario ha enviado el formulario.

3. Evitamos que la página se recargue al pulsar "submit", usando el método preventDefault().

4. Creamos una variable para almacenar la puntuación del usuario y un array para almacenar las respuestas del usuario. Podemos capturar las respuestas a través del form.(id).value form.(name).valueEsto lo explicamos en detalle en la DOM Saga. Ya que en nuestro caso el atributo que tenemos en nuestro index.html es el name, ése es el que usamos para acceder al valor de cada <input> del <form>.

En el caso de los radio buttons, lo que hace JS cuando le pedimos el valor de un <input> de tipo radio, es darnos el valor del radio button que esté seleccionado. Es decir, como hemos marcado que por cada pregunta, la primera opción esté seleccionada por defecto (usando el atributo checked), eso le indica a JS que el valor de todas las preguntas es "A".

5. Comparamos las respuestas del usuario con las respuestas correctas. Para eso, barremos con el forEach loop el array de respuestas del usuario y extraemos una respuesta individual y un índice.​​​​ Recuerda que el índice es la posición de cada elemento en el array, empezando por cero.

La comparación la hacemos comprobando si cada respuesta del usuario coincide con algún elemento del array de respuestas correctas. A los elementos del array de respuestas correctas podemos acceder a través del parámetro index.

Por cada respuesta acertada, le daremos 25 puntos. 

Hacemos un console.log de la puntuación para comprobar que nuestro código funcione.

Aquí el bloque de código que hemos añadido:​​

const correctAnswers = ["B", "B", "A", "B"];
const form = document.querySelector(".quiz-form");

form.addEventListener("submit", e => {
  e.preventDefault();
  let score = 0;
  const userAnswers = [
    form.q1.value,
    form.q2.value,
    form.q3.value,
    form.q4.value
  ];

  // check answers
  userAnswers.forEach((answer, index) => {
    if (answer === correctAnswers[index]) {
      score += 25;
    }
  });

  console.log(score);
});

Guarda los cambios, ve a tu navegador y prueba a seleccionar alguna respuesta y enviar el formulario. Verás como en tu consola se va actualizando el resultado a medida que marcas diferentes opciones y le das a "enviar".

Mostrando la puntuación en la página

Ahora que ya sabemos cómo mostrar la puntuación que ha obtenido que usuario, vamos a mostrarla en la pantalla para que el usuario pueda verla. 

1. Definimos una estructura HTML en nuestro index.html. Fíjate que por defecto, este bloque de código está oculto. Nos encargaremos de hacerlo visible con JS.

Aquí el bloque de código que hemos añadido, a continuación de la top section:​​

    <!--************************* result section **********************************-->
    <div class="result d-none py-4 bg-light text-center">
        <div class="container lead">
            <p>You are <span class="text-primary display-4 p-3">0%</span> JavaScript ninja</p>
        </div>
    </div>

2. Vamos a nuestro app.js y creamos una referencia tanto para el <div> que engloba el resultado final como para el <span> que contiene el resultado concreto.

3. Le eliminamos la clase d-none de Bootstrap al <div> del resultado. Esta era la clase que lo mantenía oculto.

4. Mostramos el resultado del usuario usando textContent.

? Los pasos 3 y 4 los hacemos dentro del scope del event listener del form.

Aquí el bloque de código que hemos añadido:

const resultContainer = document.querySelector('.result');
let finalScore = document.querySelector('.result span');

// show score on page
resultContainer.classList.remove('d-none');
finalScore.textContent = `${score}%`;

Haz el cuestionario de nuevo, envíalo y ¡voilà! Sube con el ratón hacia arriba para ver tu resultado. ?

La verdad que es un poco molesto eso de tener que subir con el ratón para ver tu puntuación, no es demasiado user-friendly. Por suerte, esto tiene fácil arreglo. ?

5. Utilizamos el método scrollTo(), proporcionado directamente desde el window object. Por tanto, no hace falta que escribamos window.scrollTo()sino simplemente scrollTo(). Este método acepta dos parámetros, que corresponden a coordenadas: la posición en píxeles en el eje X y la posición en el eje Y. 

Como queremos posicionarnos en la parte más alta de la pantalla para que nos lleve ahí, le damos unas coordenadas de 0,0.

Aquí la línea de código que hemos añadido, justo arriba del código que muestra la puntuación en la pantalla:

  // show score on page
  scrollTo(0, 0);

Animaciones con el método setInterval()

Hemos conseguido mostrar la puntuación del usuario y llevarlo al principio de la pantalla sin que tenga que subir con el ratón. ¡Chachi! ? Pero lo cierto es que la puntuación se muestra de repente, de manera un poco brusca

Vamos a arreglar eso añadiendo un efecto de transición, como un marcador que va de 0 a un número X pasando por todos los números anteriores muy rápido. Esto lo vamos a conseguir usando el método proporcionado directamente por el window object, el setInterval.

Este método acepta una callback function y un intervalo como argumentos, en ese orden. La callback function se repetirá cada X mili-segundos, según le indiquemos en el intervalo.

Sintaxis:

setInterval(() => {
  // código aquí
}, intervalo en mili-segundos);


Vamos a hacer un ejemplo para entenderlo bien. ?

1. Creamos un método setInterval y hac​​emos un console.log dentro de la callback function.  Le decimos que se ejecute cada 1000 mili-segundos (un segundillo). Así lo haríamos:

setInterval(() => {
  console.log('tomorrow is friday');
}, 1000);

Si guardas y vas a tu consola, verás que la frase se imprime cada 1 segundo. ¡Chachi! Pero tan importante es saber crear una función setInterval como saber pararla?

2. Para aprender a pararla, declaramos una variable global a la que llamamos y le damos un valor de 0. Dentro de la callback function incrementamos en +1, y le pedimos que se repita cada 1 segundo (como antes).

3. Guardamos la función setInterval en una variable llamada tomorrowsDate, por ejemplo.

4. Comprobamos si es igual a un número, 5, por ejemplo. Cosa que ocurrirá a la quinta vez que se dispare la callback function.

5. Cuando se cumpla esa condición, paramos el setInterval usando el método clearInternval sobre la variable que recoge el setInterval (tomorrowsDate).​​​​

Aquí el bloque de código que hemos editado:

let i = 0;
const tomorrowsDate = setInterval(() => {
  i++;
  console.log("tomorrow is friday");
  if (i === 5) {
    clearInterval(tomorrowsDate);
  }
}, 1000);

Si guardas y vas a tu consola, verás que la frase "tomorrow is friday" se repite 5 veces y luego se para ¡Genial!

Vamos a aplicar estos conocimientos para crear nuestro marcador. Comenta el código que acabamos de hacer para que no te moleste.

? Recuerda que estamos trabajando sobre lo que ocurre cuando hacemos click en el botón "submit", por tanto, toda nuestra lógica de programación sigue estando dentro del event listener aplicado al form.

6. Creamos una variable que será la encargada de llevar la cuenta de cuántas veces se dispara nuestra callback function. La llamamos points y le damos el valor de 0. Ésta será la variable que vaya desde 0 hasta el número de puntos que haya conseguido el usuario, que recordemos, pueden ser 0, 25, 75 o 100.

7. Creamos un método setInterval y lo guardamos en una variable a la que llamamos timer. Dentro de la callback function vamos a necesitar mostrar el resultado en la pantalla, cosa que ya hemos hecho en el apartado de //show score on pageAsí que cogemos esta línea de código:

  finalScore.textContent = `${score}%`;

 y la pegamos dentro de la callback function. 

? Aquí viene el quid de la cuestión. Ya no queremos mostrar el score en la pantalla, porque sería un valor estático. Lo que queremos mostrar es el valor de la variable points, que vamos a hacerla coincidir con la puntuación que el usuario consiga. Después, la haremos subir de 0 a la puntuación conseguida.

8. Para eso, hacemos una comprobación igual que en el ejemplo de arriba. Comprobamos si la variable points es igual que la variable score, y si aún no lo es, le sumamos +1 a la variable points. Pero si lo es (else), paramos la función timer usando el clearInterval. 

9. Como toque final, le añadimos un intervalo de tiempo al setInterval (recordemos que espera dos parámetros). Le damos unos 10 mili-segundos para que la animación sea muy rápida y dinámica.

Aquí el bloque de código que hemos editado/añadido:

  // show score on page
  scrollTo(0, 0);
  resultContainer.classList.remove("d-none");
  
  // animate score
  let points = 0;
  
  const timer = setInterval(() => {
    finalScore.textContent = `${points}%`;
    if(points === score) {
      clearInterval(timer);
    } else {
      points++;
    }
  }, 10);

THE END!

¡Fin del proyecto! Espero que hayas aprendido algo nuevo ?.  Si te queda alguna duda, ¡nos vemos en los comentarios!

Y si crees que este post puede serle útil a alguien, ¡compártelo!

Otros artículos que pueden interesarte

Cómo aprendí a programar cuando estaba «programada» para ser de letras
[tcb-script src="https://player.vimeo.com/api/player.js"][/tcb-script]A nadie le gusta su trabajo. Eso es lo que me decía a mí misma cuando conseguí mi primer[...]
Días del 160 al 203 – ¡Primer objetivo conseguido!
“A veces podemos pasarnos años sin vivir en absoluto, y de pronto toda nuestra vida se concentra en un solo[...]
Claves para entender Angular. Qué es y cómo se utiliza
Angular es un framework creado por Google que nos permite construir Single Page Applications (SPA, por sus siglas en inglés).Frameworks¿Pero qué es[...]
Si crees que este post puede serle útil a alguien, por favor, ¡compártelo!:

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Esta web utiliza cookies para asegurar que se da la mejor experiencia al usuario. Si continúas utilizando este sitio se asume que estás de acuerdo. más información

Los ajustes de cookies en esta web están configurados para «permitir las cookies» y ofrecerte la mejor experiencia de navegación posible. Si sigues usando esta web sin cambiar tus ajustes de cookies o haces clic en «Aceptar», estarás dando tu consentimiento a esto.

Cerrar