Implementación de un Cuestionario Dinámico con JavaScript y AlertifyJS
Implementación de un Quiz Interactivo con JavaScript y jQuery
A continuación se presenta y detalla el código estructurado para la creación de un cuestionario interactivo temático (Stranger Things) que gestiona la carga asíncrona de datos desde un archivo JSON mediante la Fetch API, el control de la interfaz mediante jQuery y la presentación de notificaciones modales con AlertifyJS.
1. Variables Globales e Inicialización
Se declaran las variables principales encargadas de almacenar tanto las preguntas cargadas como las selecciones realizadas por el usuario:
let preguntas = [];
let respuestasUsuario = [];
// BOTÓN COMENZAR
$(".boton-iniciar").click(function () {
$("#pantalla-inicio").addClass("oculto");
$("#pantalla-quiz").removeClass("oculto");
cargarPreguntas();
});2. Carga de Preguntas con Fetch API
La función cargarPreguntas() obtiene los datos desde un archivo externo de forma asíncrona y gestiona posibles excepciones de red:
// CARGAR JSON CON FETCH
function cargarPreguntas() {
fetch("files/preguntasST.json")
.then(response => response.json())
.then(data => {
preguntas = data.preguntas;
mostrarPreguntas();
})
.catch(error => {
console.error(error);
alertify.error("Error al cargar las preguntas");
});
}3. Renderizado Dinámico de Preguntas en el DOM
La función mostrarPreguntas() itera sobre el arreglo de preguntas y sus respectivas opciones para generar el marcado HTML necesario:
// MOSTRAR PREGUNTAS
function mostrarPreguntas() {
let html = "";
preguntas.forEach((pregunta, indice) => {
html += `
<div class="bloque-pregunta">
<p><strong>Pregunta ${indice + 1}:</strong> ${pregunta.pregunta}</p>
<div class="opciones">`;
pregunta.opciones.forEach((opcion, indiceOpcion) => {
html += `
<button type="button"
class="boton-opcion"
data-pregunta="${indice}"
data-opcion="${indiceOpcion}">
${opcion}
</button>`;
});
html += `
</div>
</div>`;
});
$("#todas-preguntas").html(html);
}4. Selección de Respuestas
Se utiliza la delegación de eventos para registrar la opción escogida por el usuario, actualizando visualmente las clases CSS correspondientes:
// SELECCIONAR RESPUESTA
$(document).on("click", ".boton-opcion", function () {
let pregunta = $(this).data("pregunta");
let opcion = $(this).data("opcion");
// QUITAR SELECCIÓN ANTERIOR
$(`button[data-pregunta='${pregunta}']`).removeClass("seleccionada");
// MARCAR NUEVA SELECCIÓN
$(this).addClass("seleccionada");
respuestasUsuario[pregunta] = opcion;
});5. Validación, Corrección y Asignación de Niveles
Al pulsar el botón de envío, el sistema valida que no existan preguntas sin responder, compara las elecciones con las respuestas correctas, resalta los aciertos o fallos y calcula el nivel obtenido por el usuario:
// COMPROBAR RESPUESTAS
$(".boton-enviar").click(function () {
// CONTAR PREGUNTAS SIN RESPONDER
let preguntasSinResponder = 0;
for (let i = 0; i < preguntas.length; i++) {
if (respuestasUsuario[i] === undefined) {
preguntasSinResponder++;
}
}
// VALIDAR
if (preguntasSinResponder > 0) {
alertify.alert(
"Preguntas pendientes",
`Debes responder todas las preguntas antes de corregir el test.<br><br>
Te faltan <b>${preguntasSinResponder}</b> pregunta(s) por responder.`
);
return;
}
let aciertos = 0;
preguntas.forEach((pregunta, indice) => {
let correcta = pregunta.correcta;
let botones = $(`button[data-pregunta='${indice}']`);
botones.each(function () {
let opcion = $(this).data("opcion");
// MARCAR CORRECTA
if (opcion == correcta) {
$(this).addClass("correcta");
}
// MARCAR INCORRECTA
if (opcion == respuestasUsuario[indice] && opcion != correcta) {
$(this).addClass("incorrecta");
}
});
// CONTAR ACIERTOS
if (respuestasUsuario[indice] == correcta) {
aciertos++;
}
});
// CALCULAR PORCENTAJE
let porcentaje = Math.round((aciertos / preguntas.length) * 100);
// EVALUAR RANGO DE PUNTUACIÓN
let nivel = "";
if (porcentaje === 100) {
nivel = "🏆 NIVEL MAESTRO DEL UPSIDE DOWN";
} else if (porcentaje >= 80) {
nivel = "⭐ EXPERTO EN STRANGER THINGS";
} else if (porcentaje >= 60) {
nivel = "🔥 FAN DEDICADO";
} else if (porcentaje >= 40) {
nivel = "👍 CONOCEDOR";
} else {
nivel = "📺 NECESITAS VER MÁS";
}
// MOSTRAR RESULTADO
alertify.alert(
"Resultado Final",
`<b>Aciertos:</b> ${aciertos}/${preguntas.length}<br>
<b>Porcentaje:</b> ${porcentaje}%<br><br>
<b>${nivel}</b>`
);
});