portada javascript ninja quiz

JavaScript Ninja Quiz

脷ltima actualizaci贸n:

驴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

D铆as del 353 al 386
Objetivos versus realidad Y nuevamente, lleg贸 otro d铆a clave. Lleg贸鈥 pas贸. El pasado 4 de marzo este Reto Computer Geek[...]
Dates en JavaScript: Gu铆a completa
Introducci贸nLos dates son un tipo de objetos de JavaScript (JS), muy 煤tiles para trabajar con fechas, como podr铆a ser la fecha de[...]
D铆as del 2 al 4
"Si buscas resultados distintos no hagas siempre lo mismo" - Albert Einstein Estos d铆as estoy aprendiendo a hacer loops en[...]

Deja un comentario

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

Como toda web legal que se precie, utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si contin煤as utilizando este sitio asumiremos que est谩s de acuerdo. m谩s informaci贸n

Los ajustes de cookies de esta web est谩n configurados para "permitir cookies" y as铆 ofrecerte la mejor experiencia de navegaci贸n posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estar谩s dando tu consentimiento a esto.

Cerrar