Trivia

screenshot of trivia questions

Problem to Solve

Write a webpage that lets users answer trivia questions.

Distribution Code

For this problem, you’ll extend the functionality of code provided to you by CS50’s staff.

Download the distribution code

Open VS Code.

Start by clicking inside your terminal window, then execute cd by itself. You should find that its “prompt” resembles the below.

$

Click inside of that terminal window and then execute

wget https://cdn.cs50.net/2023/spring/psets/8/trivia.zip

followed by Enter in order to download a ZIP called trivia.zip in your codespace. Take care not to overlook the space between wget and the following URL, or any other character for that matter!

Now execute

unzip trivia.zip

to create a folder called trivia. You no longer need the ZIP file, so you can execute

rm trivia.zip

and respond with “y” followed by Enter at the prompt to remove the ZIP file you downloaded.

Now type

cd trivia

followed by Enter to move yourself into (i.e., open) that directory. Your prompt should now resemble the below.

trivia/ $

If all was successful, you should execute

ls

and you should see an index.html file and a styles.css file.

If you run into any trouble, follow these same steps again and see if you can determine where you went wrong!

Implementation Details

Design a webpage using HTML, CSS, and JavaScript to let users answer trivia questions.

  • In index.html, add beneath “Part 1” a multiple choice trivia question of your choosing with HTML.
    • You should use an h3 heading for the text of your question.
    • You should have one button for each of the possible answer choices. There should be at least three answer choices, of which exactly one should be correct.
  • Using JavaScript, add logic so that the buttons change colors when a user clicks on them.
    • If a user clicks on a button with an incorrect answer, the button should turn red and text should appear beneath the question that says “Incorrect”.
    • If a user clicks on a button with the correct answer, the button should turn green and text should appear beneath the question that says “Correct!”.
  • In index.html, add beneath “Part 2” a text-based free response question of your choosing with HTML.
    • You should use an h3 heading for the text of your question.
    • You should use an input field to let the user type a response.
    • You should use a button to let the user confirm their answer.
  • Using JavaScript, add logic so that the text field changes color when a user confirms their answer.
    • If the user types an incorrect answer and presses the confirmation button, the text field should turn red and text should appear beneath the question that says “Incorrect”.
    • If the user types the correct answer and presses the confirmation button, the input field should turn green and text should appear beneath the question that says “Correct!”.

Optionally, you may also:

  • Edit styles.css to change the CSS of your webpage!
  • Add additional trivia questions to your trivia quiz if you would like!

Hints

Run http-server to render your webpage

Before adding questions to your Trivia site, it’s best to first take a look at how it renders! In your trivia folder, run http-server. Then, click on the link provided.

Inside the head element, the page’s stylesheets and title are specified for you. You can see this site loads a font from fonts.googleapis.com and applies the CSS in styles.css. Notice too that there’s a some space to write JavaScript in the script element, but more on that later!

<head>
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500&display=swap" rel="stylesheet">
    <link href="styles.css" rel="stylesheet">
    <title>Trivia!</title>
    <script>
        // TODO: Add code to check answers to questions
    </script>
</head>

Look inside the body element and you’ll see you have two places to write trivia questions:

<div class="section">
    <h2>Part 1: Multiple Choice </h2>
    <hr>
    <!-- TODO: Add multiple choice question here -->
</div>
<div class="section">
    <h2>Part 2: Free Response</h2>
    <hr>
    <!-- TODO: Add free response question here -->
</div>

Each of these sections is denoted by a div with class section (fitting!). A div is an HTML element that can function as a divider between sections of your page. Though they aren’t rendered, they’re useful for applying styles to certain segments of a page. See the CSS associated with the section class in styles.css if you’re curious what CSS properties this div applies to its children.

Use HTML's h3, button, and input elements to add questions to your webpage

Consider the components you’ll need to make a question on your page. You’ll need the question text itself, followed by a way for the user to enter their answer, whether in the form of a button or an input box.

Consider writing your question’s text in a heading element. An h3 might work best, given that it’s one step smaller than an h2—the heading size currently used for each section’s title.

<div class="section">
    <h2>Part 1: Multiple Choice </h2>
    <hr>
    <h3>What is the approximate ratio of people to sheep in New Zealand?</h3>
</div>
<div class="section">
    <h2>Part 2: Free Response</h2>
    <hr>
    <h3>In which country is it illegal to own only one guinea pig, as a lone guinea pig might get lonely?</h3>
</div>

Now, consider how to let a user input their answer. For a multiple choice question, you could add a sequence of buttons, as below.

<div class="section">
    <h2>Part 1: Multiple Choice </h2>
    <hr>
    <h3>What is the approximate ratio of people to sheep in New Zealand?</h3>
    <button>6 people per 1 sheep</button>
    <button>3 people per 1 sheep</button>
    <button>1 person per 1 sheep</button>
    <button>1 person per 3 sheep</button>
    <button>1 person per 6 sheep</button>
</div>

Or, for a free-response question, you could add an input box with a button to submit the answer.

<div class="section">
    <h2>Part 2: Free Response</h2>
    <hr>
    <h3>In which country is it illegal to own only one guinea pig, as a lone guinea pig might get lonely?</h3>
    <input type="text"></input>
    <button>Check Answer</button>
</div>

Try refreshing your page to see these elements rendered. Be sure they look as you intend!

Use JavaScript's querySelector, querySelectorAll, and addEventListener functions to add interactivity

Developers commonly use JavaScript to add interactivity to webpages. Often, they will select certain HTML elements from the page and apply an event listener to them. An event listener waits for some action to occur on a particular element and, when it does, runs the function specified by the developer.

Before you can use JavaScript to select elements from your page, you’ll first need to wait for the page to load. The process of waiting can itself be implemented as an event listener. In this case, you can add an event listener to the document, which is the root element of your HTML. You can add an event listener to an object using a method called, well, addEventListener! The event to listen for will be DOMContentLoaded, which is the signal that all HTML elements have been loaded.

document.addEventListener('DOMContentLoaded', function() {
    // Function to run when DOM content is loaded
});

Notice that the function to run is indeed blank for now. But consider what you might add!

Focus first, perhaps, on allowing the user to guess an answer to your multiple choice question. Write some pseudocode to remind you what to do:

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
});

Consider how you could designate some buttons as “correct” and other buttons as “incorrect.” Applying a CSS class can be a good way to help you select all elements of a certain category.

<div class="section">
    <h2>Part 1: Multiple Choice </h2>
    <hr>
    <h3>What is the approximate ratio of people to sheep in New Zealand?</h3>
    <button class="incorrect">6 people per 1 sheep</button>
    <button class="incorrect">3 people per 1 sheep</button>
    <button class="incorrect">1 person per 1 sheep</button>
    <button class="incorrect">1 person per 3 sheep</button>
    <button class="correct">1 person per 6 sheep</button>
</div>

Now that you’ve applied a CSS selector (a class!) to each button, consider document.querySelectorAll. document.querySelectorAll is a function that returns a list of all elements on the document retrieved by the selector given as input.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
});

Now, you can indeed iterate over a list in JavaScript, much as you would in C or Python. Moreover, you can apply an event listener to each item, a button, in that list—one that will itself run a function to update the style of the button.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    // Add event listeners to correct buttons
    for (let i = 0; i < corrects.length; i++) {
        corrects[i].addEventListener('click', function() {

            // Set background color to green
            corrects[i].style.backgroundColor = 'Green';
        });
    }

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
});

Of course, you need to not only update the style of the button, but also display some textual feedback. Consider creating an empty p tag where you could eventually display some text.

<div class="section">
    <h2>Part 1: Multiple Choice </h2>
    <hr>
    <h3>What is the approximate ratio of people to sheep in New Zealand?</h3>
    <button class="incorrect">6 people per 1 sheep</button>
    <button class="incorrect">3 people per 1 sheep</button>
    <button class="incorrect">1 person per 1 sheep</button>
    <button class="incorrect">1 person per 3 sheep</button>
    <button class="correct">1 person per 6 sheep</button>
    <p id="feedback1"></p>
</div>

You might recall from lecture that the innerHTML property can update the HTML between an element’s tags. You could, then, select this particular p element and, from there, update that element’s innerHTML. To select this element, you need only use querySelector—a version of querySelectorAll that returns only the first element on the page that matches the given selector.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    // Add event listeners to correct buttons
    for (let i = 0; i < corrects.length; i++) {
        corrects[i].addEventListener('click', function() {

            // Set background color to green
            corrects[i].style.backgroundColor = 'Green';

            // Add "Correct!" feedback
            document.querySelector('#feedback1').innerHTML = 'Correct!';
        });
    }

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
});

And that’s it! Any buttons with the class correct should turn green when clicked. Some feedback should also be displayed to the user. Now, do the same for the incorrect buttons, but adjust the event listener accordingly.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    // Add event listeners to correct buttons
    for (let i = 0; i < corrects.length; i++) {
        corrects[i].addEventListener('click', function() {

            // Set background color to green
            corrects[i].style.backgroundColor = 'Green';

            // Add "Correct!" feedback
            document.querySelector('#feedback1').innerHTML = 'Correct!';
        });
    }

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
    
    // Select incorrect buttons
    let incorrects = document.querySelectorAll('.incorrect');
    
    // Add event listeners to incorrect buttons
    for (let i = 0; i < incorrects.length; i++) {
        incorrects[i].addEventListener('click', function() {

            // Set background color to red
            incorrects[i].style.backgroundColor = 'Red';

            // Add "Incorrect" feedback
            document.querySelector('#feedback1').innerHTML = 'Incorrect';
        });
    }
});

Now for the final few steps! Turn to implementing your free response question. But first, you’ll likely want to add a few selectors to these elements, so you can select them via JavaScript.

<div class="section">
    <h2>Part 2: Free Response</h2>
    <hr>
    <h3>In which country is it illegal to own only one guinea pig, as a lone guinea pig might get lonely?</h3>
    <p id="feedback2"></p>
    <input type="text"></input>
    <button id="check">Check Answer</button>
</div>

Ideally, a user should be able to check their answer when they click on the button with the id of check. Go ahead and create an event listener that button.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    // Add event listeners to correct buttons
    for (let i = 0; i < corrects.length; i++) {
        corrects[i].addEventListener('click', function() {

            // Set background color to green
            corrects[i].style.backgroundColor = 'Green';

            // Add "Correct!" feedback
            document.querySelector('#feedback1').innerHTML = 'Correct!';
        });
    }

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
    
    // Select incorrect buttons
    let incorrects = document.querySelectorAll('.incorrect');
    
    // Add event listeners to incorrect buttons
    for (let i = 0; i < incorrects.length; i++) {
        incorrects[i].addEventListener('click', function() {

            // Set background color to red
            incorrects[i].style.backgroundColor = 'Red';

            // Add "Incorrect" feedback
            document.querySelector('#feedback1').innerHTML = 'Incorrect';
        });
    }

    /* Check free response submission */

    // Add event listener to check button
    document.querySelector('#check').addEventListener('click', function() {
        
        // Check for correct answer
    });
});

How to check for the correct answer? You’ll first need to select the input element. Once you do, you can access the text inside it via its value property.

document.addEventListener('DOMContentLoaded', function() {

    /* When any correct answer is clicked, change button color to green and display "Correct!" */
    
    // Select correct buttons
    let corrects = document.querySelectorAll('.correct');

    // Add event listeners to correct buttons
    for (let i = 0; i < corrects.length; i++) {
        corrects[i].addEventListener('click', function() {

            // Set background color to green
            corrects[i].style.backgroundColor = 'Green';

            // Add "Correct!" feedback
            document.querySelector('#feedback1').innerHTML = 'Correct!';
        });
    }

    /* When any incorrect answer is clicked, change button color to red and display "Incorrect" */
    
    // Select incorrect buttons
    let incorrects = document.querySelectorAll('.incorrect');
    
    // Add event listeners to incorrect buttons
    for (let i = 0; i < incorrects.length; i++) {
        incorrects[i].addEventListener('click', function() {

            // Set background color to red
            incorrects[i].style.backgroundColor = 'Red';

            // Add "Incorrect" feedback
            document.querySelector('#feedback1').innerHTML = 'Incorrect';
        });
    }

    /* Check free response submission */

    // Add event listener to check button
    document.querySelector('#check').addEventListener('click', function() {

        // Select input element
        let input = document.querySelector('input');

        // Test input element's value
        if (input.value === 'Switzerland') {
            input.style.backgroundColor = 'green';
            document.querySelector('#feedback2').innerHTML = 'Correct!';
        }
        else {
            input.style.backgroundColor = 'red';
            document.querySelector('#feedback2').innerHTML = 'Incorrect';
        }
    });
});

And that’s all for your free response question! Try reloading the page to test your JavaScript.

Walkthrough

Not sure how to solve?

How to Test

No check50 for this problem, as implementations will vary based on your questions! But be sure to test both incorrect and correct responses for each of your questions to ensure that your webpage responds appropriately.

Run http-server in your terminal while in your trivia directory to start a web server that serves your webpage.

How to Submit

  1. Download your index.html and styles.css files by control-clicking or right-clicking on the file in your codespace’s file browser and choosing Download.
  2. Go to CS50’s Gradescope page.
  3. Click Problem Set 8: Trivia.
  4. Drag and drop your index.html and styles.css files to the area that says Drag & Drop. Be sure they have those exact filenames! If you upload a file with a different name, the autograder likely will fail when trying to run it, and ensuring you have uploaded files with the correct filenames is your responsibility!
  5. Click Upload.

You should see a message that says “Problem Set 8: Trivia submitted successfully!”