I have been developing a Trivia game for years now using Vanilla JavaScript and I finally using AI to help me. Yes, I know some people consider it cheating, but you still need to know how to code and do HTML/CSS as AI isn’t perfect and I can tell you there have been plenty of times that I felt like I was arguing with a person. I have this broken down in modules and commented (AI help me with that), but I thought I like to share as it gives a pretty good breakdown of the code.
Here’s the basic HTML
<main id="content" class="main">
<div class="image-header">
<img src="assets/images/img-brainwave-header.jpg" alt="Brain Wave Blitz">
</div>
<div id="quiz" class="displayMessage">
<!-- Main game section, initially hidden -->
<div id="mainGame" style="display: none;">
<!-- Section for displaying the question and answers -->
<div id="triviaSection">
<div id="questionBox">
<!-- Current question and score information -->
<div id="current" class="info-bar">
<p>Current question is <span id="currentQuestion" data-record=""></span></p>
<p>Your score: <span id="score">0</span></p>
</div>
<h2 id="question">Question Goes Here!</h2>
<div id="answers">
<button class="buttonStyle" id="ans1"></button>
<button class="buttonStyle" id="ans2"></button>
<button class="buttonStyle" id="ans3"></button>
<button class="buttonStyle" id="ans4"></button>
</div>
<!-- Area for showing whether the answer was correct or not -->
<p id="result"></p>
</div>
<!-- Next button for moving to the next question -->
<button id="next" class="nextBtn">Next</button>
</div>
</div>
</div>
<!-- Selector for choosing the category of questions -->
<div id="categorySelector">
<label for="category">Choose a category:</label>
<select id="category" name="category">
<option value="">--Please choose a category--</option>
<option value="lego">LEGO</option>
<option value="photography">Photography</option>
<option value="space">Space</option>
<option value="movie">Movies</option>
<option value="sport">Sports</option>
</select>
</div>
</main>
this is the main JavaScript module called main.js
which is appropriate
// Import necessary modules
import Game from "./game.js"; // Game logic module
import UI from "./ui.js"; // User interface module
import API from "./api.js"; // API interaction module
// Create instances of the Game, UI, and API classes
const game = new Game();
const ui = new UI();
const api = new API();
// Event listener for category selection changes
ui.categorySelect.addEventListener("change", () => {
// Get the selected category value
const selectedCategory = ui.categorySelect.value;
// Reset the game state
game.resetGame();
// Enable answer buttons
ui.enableButtons();
// Check if a category is selected
if (selectedCategory) {
// Display the main game elements
ui.displayMainGame();
// Fetch trivia questions and answers from the API
api.fetchTriviaQuestionsAnswers(`fetch_questions.php?category=${selectedCategory}`)
// Start the game with the fetched data
.then(data => game.startGame(data))
// Catch and log any errors
.catch(error => console.error(error));
} else {
// Hide the main game elements if no category is selected
ui.hideMainGame();
}
});
// Event listener for the next button click
ui.nextButton.addEventListener("click", () => {
// Proceed to the next question in the game
game.nextQuestion();
// Update the UI after proceeding to the next question
ui.updateUIAfterNextQuestion();
});
and you would put that in your HTML →
<!-- Link to the external JavaScript file -->
<script type="module" src="assets/js/main.js"></script>
next is the api.js
:
// Define the API class to handle API requests
class API {
// Constructor method to initialize the API class
constructor() {}
/**
* Fetch trivia questions and answers from the specified URL
*
* @param {string} url - The URL to send the GET request to
* @returns {Promise} A promise that resolves with the fetched data in JSON format
*/
fetchTriviaQuestionsAnswers(url) {
// Send a GET request to the specified URL
return fetch(url)
// Handle any errors that occur during the request
.then((response) => this.handleErrors(response))
// Parse the response data as JSON
.then((data) => data.json())
// Catch and log any errors that occur during the request
.catch((error) => console.error(error));
}
/**
* Fetch the correct answer for a given question ID
*
* @param {number} id - The ID of the question to fetch the correct answer for
* @returns {Promise} A promise that resolves with the fetched data in JSON format
*/
fetchCorrectAnswer(id) {
// Send a POST request to the server with the question ID
return fetch('fetch_correct_answer.php', {
method: 'POST',
body: JSON.stringify({ id: id })
})
// Handle any errors that occur during the request
.then((response) => this.handleErrors(response))
// Parse the response data as JSON
.then((data) => data.json())
// Catch and log any errors that occur during the request
.catch((error) => console.error(error));
}
/**
* Handle errors that occur during API requests
*
* @param {Response} response - The response object from the server
* @returns {Response} The response object if it's OK, or throws an error if it's not
*/
handleErrors(response) {
// Check if the response status is OK (200-299)
if (!response.ok) {
// Throw an error if the response status is not OK
throw response.status + " : " + response.statusText;
}
// Return the response object if it's OK
return response;
}
}
// Export the API class as the default export
export default API;
the ui.js
module:
// Define the UI class to handle user interface updates and interactions
class UI {
// Constructor method to initialize the UI class
constructor() {
// Select the category select element from the DOM
this.categorySelect = document.querySelector("#category");
// Select the main game container from the DOM
this.mainGame = document.querySelector("#mainGame");
// Select the brainwave header element from the DOM
this.brainwaveheader = document.querySelector(".image-header");
// Select the next button element from the DOM
this.nextButton = document.querySelector("#next");
// Select all answer button elements from the DOM
this.answerButtons = document.querySelectorAll(".buttonStyle");
}
/**
* Enable Answer Buttons
*
* Enables all answer buttons to allow user input.
*/
enableButtons() {
// Iterate over each answer button and set its disabled property to false
this.answerButtons.forEach(button => {
button.disabled = false;
});
}
/**
* Disable Answer Buttons
*
* Disables all answer buttons to prevent user input.
*/
disableButtons() {
// Iterate over each answer button and set its disabled property to true
this.answerButtons.forEach(button => {
button.disabled = true;
});
}
/**
* Show Next Button
*
* Displays the next button to allow the user to proceed to the next question.
*/
showNextButton() {
// Set the display property of the next button to "block" to make it visible
this.nextButton.style.display = "block";
}
/**
* Hide Next Button
*
* Hides the next button to prevent the user from proceeding to the next question.
*/
hideNextButton() {
// Set the display property of the next button to "none" to make it invisible
this.nextButton.style.display = "none";
}
/**
* Display Main Game
*
* Displays the main game container and hides the brainwave header.
*/
displayMainGame() {
// Set the display property of the main game container to "block" to make it visible
this.mainGame.style.display = "block";
// Set the display property of the brainwave header to "none" to make it invisible
this.brainwaveheader.style.display = "none";
}
/**
* Hide Main Game
*
* Hides the main game container.
*/
hideMainGame() {
// Set the display property of the main game container to "none" to make it invisible
this.mainGame.style.display = "none";
}
/**
* Update UI After Next Question
*
* Hides the next button and enables the answer buttons after the user proceeds to the next question.
*/
updateUIAfterNextQuestion() {
// Hide the next button
this.hideNextButton();
// Enable the answer buttons
this.enableButtons();
}
}
// Export the UI class as the default export
export default UI;
and finally the game.js
module:
// Import the API class from the api.js module
import API from './api.js';
/**
* Game Class
*
* Handles game logic and interactions.
*/
class Game {
/**
* Constructor
*
* Initializes the Game class by setting initial game state and creating an instance of the API class.
*/
constructor() {
// Initialize game state variables
this.index = 0; // Current question index
this.triviaData = []; // Array of trivia questions and answers
this.score = 0; // Player's current score
this.choice = 0; // Player's current answer choice
// Create an instance of the API class for making API requests
this.api = new API();
}
/**
* Start Game
*
* Initializes the game with the provided trivia data and displays the first question.
*
* @param {array} data - The trivia data to use for the game.
*/
startGame(data) {
// Set the trivia data for the game
this.triviaData = data;
// Reset game state variables
this.index = 0;
this.score = 0;
this.choice = 0;
// Display the first question
this.displayQuestion();
// Hide the next button initially
document.querySelector("#next").style.display = "none";
}
/**
* Display Question
*
* Displays the current question and its possible answers.
*/
displayQuestion() {
// Get the current question from the trivia data
const currentQuestion = this.triviaData[this.index];
// Set the current question's ID as a data attribute on the #currentQuestion element
document.querySelector("#currentQuestion").setAttribute("data-record", currentQuestion.id);
// Display the current question number
document.querySelector("#currentQuestion").textContent = (this.index + 1).toString();
// Display the current question text
document.querySelector("#question").textContent = currentQuestion.question;
// Display the possible answers for the current question
this.displayAnswers(currentQuestion);
}
/**
* Display Answers
*
* Displays the possible answers for the given question.
*
* @param {object} question - The question object containing the possible answers.
*/
displayAnswers(question) {
// Get all answer button elements
const answerButtons = document.querySelectorAll(".buttonStyle");
// Iterate over each answer button
answerButtons.forEach((button, index) => {
// Remove any existing event listener for the button
const previousPickAnswer = button.__pickAnswer__;
if (previousPickAnswer) {
button.removeEventListener("click", previousPickAnswer);
}
// Create a new event listener for the button
const newPickAnswer = this.pickAnswer(index + 1);
button.addEventListener("click", newPickAnswer, false);
button.__pickAnswer__ = newPickAnswer;
// Get the answer text for the current button
let answerText = [question.ans1, question.ans2, question.ans3, question.ans4][index];
// Display the answer text on the button
if (answerText) {
button.textContent = `📷 ${answerText}`;
button.style.display = "block"; // Show the button
button.style.pointerEvents = "auto"; // Enable the button
} else {
button.textContent = "";
button.style.display = "none"; // Hide the button
button.style.pointerEvents = "none"; // Disable the button
}
});
}
/**
* Check Answer Against Table
*
* Checks the player's answer against the correct answer and updates the game state accordingly.
*
* @param {object} data - The correct answer data from the API.
*/
checkAnswerAgainstTable(data) {
// Get the correct answer from the data
const correctAnswer = data.correct;
// Increment the question index
this.index++;
// Check if the player's answer is correct
if (correctAnswer === this.choice) {
// Display a success message
document.querySelector("#result").textContent = "The answer was indeed number " + correctAnswer + "!";
document.querySelector("#result").style.color = "green";
// Increment the player's score
this.score++;
document.querySelector("#score").textContent = `${this.score}`;
} else {
// Display an error message
document.querySelector("#result").textContent = "Incorrect. The correct answer was: " + correctAnswer;
document.querySelector("#result").style.color = "red";
}
}
/**
* Pick Answer
*
* Creates an event listener for the given answer index.
*
* @param {number} answerIndex - The index of the answer to create an event listener for.
* @returns {function} The event listener function.
*/
pickAnswer(answerIndex) {
return () => {
// Set the player's answer choice
this.choice = answerIndex;
// Check the answer
this.checkAnswer();
// Show the next button if there are more questions
if (this.index < this.triviaData.length - 1) {
document.querySelector("#next").style.display = "block"; // Show the next button
document.querySelector("#next").addEventListener("click", () => {
console.log('Index before nextQuestion:', this.index);
this.nextQuestion();
console.log('Index after nextQuestion:', this.index);
document.querySelector("#next").style.display = "none"; // Hide the next button
}, { once: true }); // Ensure the event listener is only triggered once per click
}
};
}
/**
* Check Answer
*
* Checks the player's answer by making an API request to the server.
*/
checkAnswer() {
// Get all answer button elements
const answerButtons = document.querySelectorAll(".buttonStyle");
// Disable the answer buttons
this.disableButtons(answerButtons);
// Get the current question's ID
const id = document.querySelector("#currentQuestion").getAttribute("data-record");
// Make an API request to check the answer
this.api.fetchCorrectAnswer(id)
.then(data => this.checkAnswerAgainstTable(data))
.catch(error => console.error(error));
}
/**
* Handle Errors
*
* Handles errors that occur during API requests.
*
* @param {Response} response - The response object from the API.
* @returns {Promise} A promise that resolves with the response data or throws an error.
*/
handleErrors(response) {
// Check if the response is not OK (200-299)
if (!response.ok) {
// Throw an error with the status code and text
throw response.status + " : " + response.statusText;
}
// Return the response data
return response.json();
}
/**
* Disable Buttons
*
* Disables the given buttons.
*
* @param {array} buttons - The buttons to disable.
*/
disableButtons(buttons) {
// Iterate over each button and set its disabled property to true
buttons.forEach(button => {
button.disabled = true;
});
}
/**
* Enable Buttons
*
* Enables the given buttons.
*
* @param {array} buttons - The buttons to enable.
*/
enableButtons(buttons) {
// Iterate over each button and set its disabled property to false
buttons.forEach(button => {
button.disabled = false;
});
}
/**
* Reset Game
*
* Resets the game state to its initial values.
*/
resetGame() {
// Reset game state variables
this.choice = 0;
this.score = 0;
document.querySelector("#result").textContent = "";
document.querySelector("#score").textContent = `${this.score}`;
}
/**
* Next Question
*
* Proceeds to the next question in the game.
*/
nextQuestion() {
// Clear the result message
this.clearResultMessage();
// Check if there are more questions
if (this.index < this.triviaData.length) {
// Display the next question
this.displayQuestion();
} else {
// Log a message indicating the game is over
console.log("Game over");
}
}
/**
* Clear Result Message
*
* Clears the result message displayed on the screen.
*/
clearResultMessage() {
// Clear the result message
document.querySelector("#result").textContent = "";
}
}
// Export the Game class as the default export
export default Game;
I think AI explains it best :
Modules:
-
Game Module (
game.js
): Handles game logic, including resetting the game state, starting the game, and proceeding to the next question. -
UI Module (
ui.js
): Manages the user interface, including displaying and hiding game elements, enabling and disabling answer buttons, and updating the UI after proceeding to the next question. -
API Module (
api.js
): Interacts with the API to fetch trivia questions and answers.
I think this will allow me to easily add features to the trivia game and I hope this will help someone out as well. I like this approach as I don’t have to learn a library or something language based off of JavaScript. Don’t get me wrong, but I learn more this way and in the process learn more of the inner workings. HTH
and yes it does work: https://www.clearwebconcepts.com/brainwaveblitz.php