Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript Arrays Multidimensional Arrays Improve the Quiz – One Solution

Andrew Whatmore
seal-mask
.a{fill-rule:evenodd;}techdegree
Andrew Whatmore
Full Stack JavaScript Techdegree Student 2,918 Points

Solution using .textContent instead of .innerHTML

.textContent

This solution uses textContent to add to the page instead of innerHTML as it’s more secure. Is this the most efficient way to do it?

Other changes:

  • it uses the singular ‘question’ if one question was correct, and plural if not.
  • it uses a parent wrapper ‘div’ for all the content added
  • the loop through the array does not happen if it’s empty.
  • if zero questions are added either correctly or incorrectly, add ‘None’ under the corresponding heading.
  • use a function for creating the heading elements, as well as one for the questions list. Call the former inside the latter. This means we don’t have to repeat the code for creating and adding the heading elements.
  • both the answer provided by the user, and the answer in the array, are converted to upper case to make the answers case insensitive to both the user and any developer adding new questions/answers to the quiz.
// 1. Create a multidimensional array to hold quiz questions and answers

const questions = [
  ["How many league championships have Manchester United won?", "20"],
  ["How many goals did Eric Cantona score for Manchester United?", "64"],
  ["Who is Manchester United's all-time leading goal scorer?", "Wayne Rooney"]
];

// 2. Store the number of questions answered correctly
let correctAnswers = 0;

// variable to store the current answer entered by user
let answer;
// create arrays to store the correct & incorrect questions separately
const correctQuestions = [];
const incorrectQuestions = [];

/* 
  3. Use a loop to cycle through each question
      - Present each question to the user
      - Compare the user's response to answer in the array
      - If the response matches the answer, the number of correctly
        answered questions increments by 1
*/

for (let i = 0; i < questions.length; i++) {
  answer = prompt(questions[i][0]).toUpperCase();
  // if the answer is correct, increment correctAnswers, and add the question to correctQuestions array
  if (answer === questions[i][1].toUpperCase()) {
    correctAnswers++;
    correctQuestions.push(questions[i][0]);
  }
  // if answer is wrong, add question to incorrectQuestions array
  else {
   incorrectQuestions.push(questions[i][0]); 
  }
}

// 4. Display the number of correct answers to the user

// parent div
// create a wrapper div and add it to the main section
let div = document.createElement('div');
document.querySelector('main').appendChild(div);

// create an element to display the number of correct questions answered, and append it to the page
let scoreDiv = document.createElement('h1');
if (correctAnswers == 1) {
  scoreDiv.textContent = `You answered ${correctAnswers} question correctly.`
} else {
  scoreDiv.textContent = `You answered ${correctAnswers} questions correctly.`
}
div.appendChild(scoreDiv);

// display which answers were correct and incorrect
// function for creating a title for each section listing either the correct or incorrect questions, and adding it to the page. Pass in the title we want
function createTitleElement(title) {
  // create a heading element, and add the title that we passed in. Then append it to the page in the wrapper
  let titleHeading = document.createElement('h2');
  titleHeading.textContent = title;
  div.appendChild(titleHeading);
}

// loop through arrays of correct and incorrect questions and display on page
// add an array of questions to loop through, and list to output the questions to
function addQuestionsList(arr) {
  // if the array is the correctQuestions, add this title
  if (arr === correctQuestions) {
    createTitleElement('You got these questions right:');
    // if not, add this title instead
  } else {
     createTitleElement('You got these questions wrong:');
  }
  // if the array is empty, add a <p> tag to say 'None'
  if (arr.length === 0) {
    let empty = document.createElement('p');
    empty.style.textAlign = 'left';
    empty.textContent = 'None.';
    div.appendChild(empty);
  } else {
    // if the array is not empty, add a list and loop through the array to add the questions to it
    // create the parent element for the list, & add it to page
    let displayQuestionsList = document.createElement('ol');
    div.appendChild(displayQuestionsList);
    // loop through the array, and add the questions to the list.
    for (let j = 0; j < arr.length; j++) {
      // create the list item for the question
      let displayQuestion = document.createElement('li');
      displayQuestion.textContent = arr[j];
      // then add the list item to the <ol> parent
      displayQuestionsList.appendChild(displayQuestion);
    }
  }
}

// run the function for correct and incorrect questions arrays
addQuestionsList(correctQuestions);
addQuestionsList(incorrectQuestions);

2 Answers

Travis Alstrand
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Travis Alstrand
Treehouse Project Reviewer

Hi there Andrew Whatmore ! 👋

Thanks for sharing your awesome work here!

From a performance standpoint, the original solution would be slightly more efficient because it performs a single DOM update but in something this size it's so small we would never notice it.

However, your revised solution is more secure, more maintainable, and handles edge cases better, which matters far more than tiny performance optimizations in a small app like this.

In real projects, correctness, clarity, and safety almost always outweigh raw DOM efficiency.

As far as .textcontent and innerHTML, in this video's solution, the user's input isn't injected into the HTML string so it's not inherently bad or dangerous here. Having said that, your approach is more defensive and future proof. I always go for textContent by default as well.

Very nice work here!

Andrew Whatmore
seal-mask
.a{fill-rule:evenodd;}techdegree
Andrew Whatmore
Full Stack JavaScript Techdegree Student 2,918 Points

Thanks Travis.

Would the above therefore have been more efficient if I had built the whole content first (using textContent as above) and then added everything to the page in one go (using one DOM update), rather than piece-by-piece like above?

Travis Alstrand
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Travis Alstrand
Treehouse Project Reviewer

Yes, it could be more efficient in a much larger app/setting, but your current approach is absolutely the right one for this context. Optimizing this small app for performance wouldn't achieve anything noticeable by any means, I just wanted to answer the original question thoroughly. You're doing fantastic! Great work!