Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript JavaScript Loops, Arrays and Objects Tracking Multiple Items with Arrays Build a Quiz Challenge, Part 1 Solution

James Croxford
James Croxford
12,593 Points

My solution with added improvements-how to show users the paired up answers to their list of wrongly answered questions?

My solution to this challenge is below. I've added a few additional features (checking for blank responses, putting responses-and subsequent checks against the array- to lower case) and so on.

There is one piece of functionality I would like to add however. Whilst my program gives the answer to incorrect responses via dialogue boxes as the quiz runs, I would like to include the correct answers at the end.

I could just print another ordered list of answers to the questions which users got wrong (similar to the variable questionsIncorrectlyAnswered, which is concatenated as part of the for loop). However this is messy- I would have a list of questions and then a list of answers not paired together.

Can anyone hint as to a possible solution here? My thoughts were in the for-loop to copy the elements from the questionAnswerPairs array into a new array 2D array each time the user gets a question wrong. I would then use a template literal string with a message (similiar to listOfIncorrectQuestions) and then use the print method to print out each pair of elements from this array at this end? This way the user knows which questions they got right, which they got wrong, and the answers to those questions at the end of the quiz.

Let me know if what I'm saying doesn't make sense. As for my current code:

let questionAnswerPairs = [
  ['What is 7 multiplied by 9 (write your answer as a number)?', '63'],
  ['What is the capital of Belgium?', 'Brussels'],
  ['Which actor plays the comic book character "Captain America" in the MCU?', 'Chris Evans'],
  ['Who is the current US president (first and last name)?', 'Donald Trump'],
  ['Which football team won the 2019 UEFA Champions League final?', 'Liverpool']
];

let numberCorrectAnswers = 0;
let questionsCorrectlyAnswered = `<ol>`;
let questionsIncorrectlyAnswered = `<ol>`;
let results;
let listOfCorrectQuestions;
let listOfIncorrectQuestions;

for (var i = 0; i < questionAnswerPairs.length; i += 1) {
  let askQuestion = prompt(questionAnswerPairs[i][0]);

  while (askQuestion === '') {
    alert("No response provided to the question! Please provide one to continue the quiz!");
    askQuestion = prompt(questionAnswerPairs[i][0]);
  }

  if (askQuestion.toLowerCase() === questionAnswerPairs[i][1].toLowerCase()) {
        numberCorrectAnswers += 1; 
        let correctMessage = alert(`Well done! ${questionAnswerPairs[i][1]} is the correct answer!`);
        questionsCorrectlyAnswered += `<li>${questionAnswerPairs[i][0]}</li>`;
  } else {
        let wrongMessage = alert(`Not quite, the answer was: ${questionAnswerPairs[i][1]}! Better luck new time!`);
        questionsIncorrectlyAnswered += `<li>${questionAnswerPairs[i][0]}</li>`;
  }
}

questionsCorrectlyAnswered += `</ol>`;
questionsIncorrectlyAnswered += `</ol>`;

function print(message) {
  document.write(message);
}

results = `<p>The Scores are in! You got ${numberCorrectAnswers} correct out of five!</p>`;
listOfCorrectQuestions = `<p>You got these questions correct:</p>
                            ${questionsCorrectlyAnswered}`;
listOfIncorrectQuestions= `<p>You got these questions wrong:</p>
                              ${questionsIncorrectlyAnswered}`;

print(results);
print(listOfCorrectQuestions);
print(listOfIncorrectQuestions);




//Improved functionality & bug fixes

//1. Could use the print function more often DONE
/* 2. put responses to lower case, and answers only when checked-
We want to anticipate input, but also have the correct captialisation shown on screen
When the answer is shown to the user if they get the question wront. DONE */
//3. Question and answer summary printed to the screen at the end with question numbers (ordered list)- which ones right and which ones wrong? DONE
//4. ask the question again if a blank response is given, rather than it be marked incorrect DONE
/*5. provide answers to wrong questions with summary print out at the end of the quiz-
Could create <ol> list to print off answers, but each answer would not be directly below question
Could copy question and answer elements to new separate array of wrongly answered questions, then incorporate this into listOfIncorrectAnswers.
For example 
`<p>You got these questions wrong:</p>
${questionsIncorrectlyAnswered[0][0]}
The answer was: ${newArray[0][1]}`;

*/

3 Answers

Steven Parker
Steven Parker
210,487 Points

In "questionsIncorrectlyAnswered", instead of just storing the question itself (questionAnswerPairs[i][0]), you could store the entire pair (questionAnswerPairs[i]).

Then when you report at the end, you can add an extra index in a loop to display both the question and the answer.

And in both cases, it would be better to use a loop to display the questions (or question/answers) instead of relying on the the system to convert an array to a string in the template literal.

Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 13,881 Points

Firstly nice to see you put quite a bit of thought into the functionality of this adding a couple of checks along the way.

For your question. You could take the approach I did originally when working through this and just use the array push method. so create an array for correctly answered questions and an array for incorrectly answered questions. you could then populate these arrays as the user answers the questions from your original question/answer array.

at the end of the quiz you would be able to provide the feedback you wanted directly from these 2 arrays.

Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 13,881 Points

as a side note when creating for loops its safer to use let as it has less chance of causing issues later

for(let i=0; i<array.length; i++)

https://wesbos.com/for-of-es6

let restricts the scope to local function scope where var leaks into the global scope

James Croxford
James Croxford
12,593 Points

Thanks for the feedback! I've got this as my current version, which incorporates this, plus the steps taken in the next class/video. I've also added documentation to get into the habit of leaving breadcrumbs for my future self to understand what I've done!

//questions stored as an array
let questionAnswerPairs = [
  ['What is 7 multiplied by 9? (write your answer as a number)', '63'],
  ['What is the capital of Belgium?', 'Brussels'],
  ['Which actor plays the comic book character "Captain America" in the MCU?', 'Chris Evans'],
  ['Who is the current US president (first and last name)?', 'Donald Trump'],
  ['Which football team won the 2019 UEFA Champions League final?', 'Liverpool']
];
//Variables declared and initialised below:
let correctAnswers = 0;
let questionResponse;
let correctlyAnsweredQuestion = [];
let incorrectlyAnsweredQuestion = [];
let resultsSummary;

/*Updated the print function to include a modern way of posting output to the HTML document/manipulating the DOM of the web page, rather than using document.write().
Targets specific ID tag to print html content inside of that element, rather than just printing to the web page generally.
getElementByID is a method of the document object that located a tag with a specific tag attached to it.

outputDiv is a variable which holds an object with a reference for a particular spot on a webpage matching the provided string.
Called the node.
*/
function print(message) {
  let outputDiv = document.getElementById('output');
  outputDiv.innerHTML = message;
}

/* Main logic loop for the program below.
This loop uses a for-loop to cycle through each question in the array, and check the stored response-provided via a prompt method- against the answer stored in each array within the questionAnswerPairs array above.

Using prompt over creating a specific variable for the question for succintness 

Validation- checks if a response is entered using a while-loop. Repeatedly asks the question indicated by the current index value of the variable i until the user provides a response.

Normalisation- to keep presentation neat, the string answers stored in questionAnswerPairs are capitalised where appropriate. Using toLowerCase() method on strings, we normalise this answer and the user input (questionReponse) to anticipate unanticipated behaviour by users.

If correct, then the int value of correctAnswers is increased by 1 accordingly.
Then we store that particular (according to the current index value of the for-loop) element from questionAnswerPairs array (itself an array comprised of a question & answer) in a new array: correctlyAnsweredQuestion.

Similarly, if the response is incorrect then this array is itself stored in an array called incorrectlyAnsweredQuestion.

Redundant feature: In both cases we put an alert to the screen to indicate if the response to the question was correct or not. Arguably not required anymore due to question/answer summary printed to the html document at the end.
*/
for (let i = 0; i < questionAnswerPairs.length; i += 1) {
  questionResponse = prompt(questionAnswerPairs[i][0]);
  while (questionResponse === '') {
    alert("No response provided to the question! Please provide one to continue the quiz!");
    questionResponse = prompt(questionAnswerPairs[i][0]);
  }
  if (questionResponse.toLowerCase() === questionAnswerPairs[i][1].toLowerCase()) {
    correctAnswers += 1;
    correctlyAnsweredQuestion.push(questionAnswerPairs[i]);
    let correctMessage = alert(`Well done! ${questionAnswerPairs[i][1]} is the correct answer!`);
  } else {
      incorrectlyAnsweredQuestion.push(questionAnswerPairs[i]);
      let wrongMessage = alert(`Not quite, the answer was: ${questionAnswerPairs[i][1]}! Better luck new time!`);
  }
}

/* Following function returns lists of questions and associated answers. 
Originally only returned a list of questions as per class, but updated as I wanted the user to also see the answers for each question at the end.

This function creates two ordered lists, which are concatenated with list elements as the function runs.
The lists/arrays we pass to this function (correctlyAnsweredQuestion & incorrectlyAnsweredQuestion) appear to be two-dimensional (see other NOTE below). Hence the notation used in each for-loop conditional statement/initialisation block of refering to each array using two index values.

Each ordered list is opened, and populated with list elements according to how many elements are inside each array we pass to it.
If the user gets 2 questions wrong for example, then incorrectlyAnsweredQuestion[] contains two elements, each comprised of two elements, a question and an answer. This function would then create one ordered list comrpised of two questions, and one ordered list containing the two associated answers.
The i variable refers to the outer array, not the inner, as the for-loop needs to cycle through each sub array before pulling internal elements from each.
*/

function htmlList(list) {
  let orderedHtmlList = `Questions: <ol>`;
  for (let i=0; i<list.length; i += 1) {
    orderedHtmlList += `<li>${list[i][0]}</li>`;
  }
  orderedHtmlList += `</ol> Answers: <ol>`;
  for (let i = 0; i < list.length; i += 1) {
    orderedHtmlList += `<li>${list[i][1]}</li>`;
  }
  orderedHtmlList += `</ol>`;
  return orderedHtmlList;
}

/* NOTE: check up this part: 
using the toString method on correctlyAnsweredQuestion & incorrectlyAnsweredQuestion
   prints q & a's in a sequential order. How can we check if an array is multidimensional or not?
  print(correctlyAnsweredQuestion.toString());
print(incorrectlyAnsweredQuestion.toString());
*/


/*this string notififes of the number of correct answers achieved by the user, followed by two calls to the htmlList function. 
On each occasion the function is passed an array. Each call to the function creates two ordered lists.
Therefore the user recieves a score, then four ordered lists preceded by tags declaring what they are.
*/
resultsSummary = `<p>You got ${correctAnswers} question(s) right.</p>
                      <p>You got these questions correct:</p>
                            ${htmlList(correctlyAnsweredQuestion)}
                      <p>You got these questions wrong:</p>
                              ${htmlList(incorrectlyAnsweredQuestion)}`;

//prints the summary to the screen by calling the print function above.
print(resultsSummary);

1) Any thoughts/improvements?

2) One thing I noticed is that when I add/push correct questions, or incorrect questions (alongside their answers) to their new arrays:

correctlyAnsweredQuestion.push(questionAnswerPairs[i]);
//or
      incorrectlyAnsweredQuestion.push(questionAnswerPairs[i]);

That correctlyAnsweredQuestion & incorrectlyAnsweredQuestion are both 2D arrays. This makes sense, but on a technical level is this because the JS language is aware of the type of elements that have been pushed to it (i.e. that it is being passed elements which themselves are arrays)? If you were given an array which had elements pushed to it (one that you hadn't explicitly written out yourself) is there a method to check if it is multidimensional or not?