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

Help with Awesome Quiz app code challenge

long winded question

Ok so here are my specific areas of confusion with the Amazing Quiz app project. In the solution video, Andrew Chalkley used a lot of ...here

  1. When selecting the elements in the DOM. We've always used getElementById and passing in the name of the id in quotes inside the parenthesis. However here, he just passed in the word id.
  displayScore: function() {
    var gameOverHTML = "<h1>Game Over</h1>";
    gameOverHTML += "<h2> Your Score is: " + quiz.score + "</h2>";
    this.populateIdWithHTML("quiz", gameOverHTML);//used the populate object below here and used the name of the id `quiz`.
  },
  populateIdWithHTML: function(id, text) {//the function takes 2 arguments, id and text
    var element = document.getElementById(id);//used the word id here
    element.innerHTML = text;
  },
  guessHandler: function(id, guess) {
    var button = document.getElementById(id);
    button.onclick = function() {
      quiz.guess(guess);
      QuizUI.displayNext();
    }

I sort of understand, vaguely, that for the display score object above, this.populateIdWithHTML("quiz", gameOverHTML); that it is going to find an element with the id of quiz and insert the game over html in that spot. What I didn't know is that I could do or how it really works, so that means I'm unable to use it later in a different project,the populateIdWithHTML object below is taking the two parameters id, and text and for the variable named element it says document.getElementById(id) it only takes the word id. Is id here a keyword, is it a reserved word or could I have changed it to say, name or div, for example. I know how it's targeting the specific id because when we call the populate id with html object we pass in the name of the id so id below in the populate id with html object is changed to that id. However this is the first time that this method of targeting html elements in the DOM was covered, or introduced. He never mentioned you could do it that way. I thought you could only put the name of the id in quotes. I'm thinking he probably used id as an argument and then when the function is called he will pass in the name of the id, that way the function is reusable? I'm guessing? Because there are many other elements with ids and i guess as i am now noticing he used that function in many places to populate the html. hmm.But still need to break it down as to the order and structure of writing it that way. So can someone break this down for me please.

  1. This part of the displayChoices object
.
displayChoices: function() {
var choices = quiz.getCurrentQuestion().choices;

for(var i = 0; i < choices.length; i++) {
  this.populateIdWithHTML("choice" + i, choices[i]);
  this.guessHandler("guess" + i, choices[i]);
} 

in the for loop I understand it's an array of choices so it makes sense to cycle through the array and display each choice. What I don't get and was never mentioned or used before in the course is, there are 2 paragraphs with the id of choice0 and choice1 respectively and 2 buttons with the id of guess0 and guess1 respectively. in the for loop when he used the populateIdWithHTML object he just put the id of choice and for the guessHandler guess. Not choice0 and choice1 or guess0 or guess1. I understand it's a loop so it will go through each one and choices.length is an array. but there is no id named choice, there is choice0 and choice1 so why is it not throwing an error? is it because of the choices[i] at the back? Also he said ("guess" + i, choices[i]) again first use of using the for loop in that way, I mean using the + operator. Now I'm writing this I'm thinking maybe it is doing this. find an id of guess + i. Since i will be index 0 it will become choice0 and the next in the cycle will be choice + i = choice1? is that a correct way to look at it. And why didn't he mention that you could concatenate in that way in a for loop? And if it's already concatenated the choice0 and choice1 at the back what is the purpose of the choices[i] at the back?

  1. Finally for this line of code
  displayProgress: function() {
    var currenQuestionNumber = quiz.currentQuestionIndex + 1;
    this.populateIdWithHTML("progress", "Question" + currenQuestionNumber + " of " + quiz.questions.length);
  }

I can see that "progress" is the id because I know there is an id of progress in the html file and that "Question" is the first part of the text that will be displayed. But if you just look at this, it looks like it is looking for two different ids. I'm sure there is a rule that the id will always come first and maybe you can't put two different ids, but I don't know that for sure because we've never covered this in the course, or did we?

  1. There's one more
  guessHandler: function(id, guess) {
    var button = document.getElementById(id);
    button.onclick = function() {
      quiz.guess(guess);
      QuizUI.displayNext();
    }
  }

This guessHandler is very confusing. So there are two parameters in the function, id and guess then in the document.getElementById(id) how does the program know to target the button id? What is the guess parameter relating to?

I'm trying to add a restartQuiz button along with the results so the person can restart the quiz, but it's not working. What am I doing wrong? I added the button as part of the displayScore string.

  displayScore: function(id) {
    var gameOverHTML = "<h1>Game Over</h1>";
    gameOverHTML += "<h2> Your Score is: " + quiz.score + "</h2>";
    gameOverHTML += "<p> Your got " + quiz.score + " out of " + quiz.questions.length + " questions correct." + "</h2>";
    if (quiz.score <= 4) {
      gameOverHTML += "<h2> You don't know me very well! </h2>";
    } else {
      gameOverHTML += "<h2> It's nice to see you've been paying attention. </h2>";
    }
    gameOverHTML += "<button id='restart' class='btn--default'> Restart Quiz. </button>";
    this.populateIdWithHTML("quiz", gameOverHTML);
  },

and my restartHandler looks like this. I've tried different things but nothing is working.

  restartHandler: function(id) {
    var restartButton = document.getElementById(id);
    restartButton.onclick = function() {
      this.displayQuestion();
      this.displayChoices();
      this.displayProgress();
    }
  },

Can someone please go over this code with me and break down what's going on here. Andrew told us in the solution video what each line of code is doing, and it's easy enough to follow along with his explanation, but I don't understand how each line of code itself is working. There's more but these are the most confusing parts. Thanks guys.

Here's the entire quiz-ui.js file

var QuizUI = {
  displayNext: function() {
    if(quiz.hasEnded()) {
      this.displayScore();
    } else {
      this.displayQuestion();
      this.displayChoices();
      this.displayProgress();

    }
  },
  displayQuestion: function() {
    this.populateIdWithHTML("question", quiz.getCurrentQuestion().text);
  },
  displayChoices: function() {
    var choices = quiz.getCurrentQuestion().choices;

    for(var i = 0; i < choices.length; i++) {
      this.populateIdWithHTML("choice" + i, choices[i]);
      this.guessHandler("guess" + i, choices[i]);
    }
  },
  displayScore: function(id) {
    var gameOverHTML = "<h1>Game Over</h1>";
    gameOverHTML += "<h2> Your Score is: " + quiz.score + "</h2>";
    gameOverHTML += "<p> Your got " + quiz.score + " out of " + quiz.questions.length + " questions correct." + "</h2>";
    if (quiz.score <= 4) {
      gameOverHTML += "<h2> You don't know me very well! </h2>";
    } else {
      gameOverHTML += "<h2> It's nice to see you've been paying attention. </h2>";
    }
    gameOverHTML += "<button id='restart' class='btn--default'> Restart Quiz. </button>";
    this.populateIdWithHTML("quiz", gameOverHTML);
  },
  populateIdWithHTML: function(id, text) {
    var element = document.getElementById(id);
    element.innerHTML = text;
  },
  guessHandler: function(id, guess) {
    var button = document.getElementById(id);
    button.onclick = function() {
      quiz.guess(guess);
      QuizUI.displayNext();
    }
  },
  restartHandler: function(id) {
    var restartButton = document.getElementById(id);
    restartButton.onclick = function() {
      this.displayQuestion();
      this.displayChoices();
      this.displayProgress();
    }
  },
  displayProgress: function() {
    var currenQuestionNumber = quiz.currentQuestionIndex + 1;
    this.populateIdWithHTML("progress", "Question " + currenQuestionNumber + " of " + quiz.questions.length);
  }
}

Steven Parker Guil Hernandez Dave McFarland

Steven Parker
Steven Parker
243,199 Points

:mailbox_with_mail: Hi, I got alerted by your tag.

But it looks like Jennifer has you thoroughly covered already!

...but for future reference, this should probably have been 3 separate questions!

3 Answers

Jennifer Nordell
seal-mask
STAFF
.a{fill-rule:evenodd;}techdegree
Jennifer Nordell
Treehouse Teacher

Hi there, SAMUEL LAWRENCE! I wasn't tagged to answer this question, but if you don't mind my input too much I can try and give it a whirl. Unfortunately, all your "points" are labeled with the number 1. So, I'll do my best to keep everything in order. Bear with me.


This is the text from your first point: "When selecting the elements in the DOM. We've always used getElementById and passing in the name of the id in quotes inside the parenthesis. However here, he just passed in the word id."

Yes and no. You say he passed in the word id, but what he did was pass in the variable id. Let's look at that bit of the code:

  populateIdWithHTML: function(id, text) {//the function takes 2 arguments, id and text
    var element = document.getElementById(id);//used the word id here
    element.innerHTML = text;
  },

This is a function with two parameters. When that function is called the first thing passed to it will be assigned to the local variable id and the second argument will be assigned to the variable text. When we call this function we're going to send it two strings. The first string will hold the id and the second will hold the text.

Later on you will see lines similar to this one:

this.populateIdWithHTML("quiz", gameOverHTML);

At this point we are sending in the string "quiz" when we call the function. Inside the function, id will now be equal to the string "quiz". Therefore, it is as if we had typed var element = document.getElementById("quiz");.


Now to your next point:

You want to understand the displayChoices method. So let's take a look at that:

displayChoices: function() {
var choices = quiz.getCurrentQuestion().choices;

for(var i = 0; i < choices.length; i++) {
  this.populateIdWithHTML("choice" + i, choices[i]);
  this.guessHandler("guess" + i, choices[i]);
} 

So first, we're going to get the choices for the current question. You don't seem to have a problem with that part so we'll move on. You also understand that it's looping through each one and performing a method on each one. The first one is the populateIdWithHTML which we just covered. So let's look at what happens in the first iteration. On the first iteration, i is equal to 0. We then run that method and send in a string. Something interesting happens in JavaScript when you use a + sign to combine a string and a number. Because it cannot tell if you mean concatenation or addition, it will always concatenate the result. You might be interested in taking a look at this thread where I explain (and show) what happens when we use the + symbol in different circumstances. In this case, we're combining the string "choice" and the number 0. The result will be the string choice0. And then we get the first choice in that array with choices[0]. We pass both of these to the populateIdWithHTML. Now in that function, id will be equal to "choice0", and text will be equal to choices[0].


To your third point:

Let's take a look at the line I suspect you have problems with:

 this.populateIdWithHTML("progress", "Question" + currenQuestionNumber + " of " + quiz.questions.length);

You say that it looks like it's looking for two ids, but again, I feel like this is a misunderstanding of what is being sent to the populateIdWithHTML function. The first thing, before the comma, will be assigned to the local variable id. Everything after the comma is the second argument. It will be assigned to the local variable text.

So again we have this:

populateIdWithHTML: function(id, text) {//the function takes 2 arguments, id and text
    var element = document.getElementById(id);//used the word id here
    element.innerHTML = text;
  },

The variable element will now contain the result of document.getElementById("progress"), because id is now equal to "progress", and the innerHTML will be set to the value stored in text which is ""Question" + currenQuestionNumber + " of " + quiz.questions.length".


And you had one more point and you're asking about the guessHandler.

So let's take a look at that:

  guessHandler: function(id, guess) {
    var button = document.getElementById(id);
    button.onclick = function() {
      quiz.guess(guess);
      QuizUI.displayNext();
    }
  }

This function says first get an element that has the id of whatever string we send to it and assign it to the variable button. When we click on that element, do whatever happens when we make a guess and then display the next. But what id does it mean? To know that we first have to find a call site.

You'll find a call the the function in the displayChoices function that we talked about previously. Remember that pesky for loop? And here's that function call:

for(var i = 0; i < choices.length; i++) {
  this.populateIdWithHTML("choice" + i, choices[i]);
  this.guessHandler("guess" + i, choices[i]);
} 

So besides populating those two choice0 and choice1 with HTML, we are also adding event listeners. We do that by calling the guessHandler method. And remember, we're concatenating a string and a number together so the result will be a string which we then send in. During the first iteration of this loop, this part this.guessHandler("guess" + i, choices[i]); would be equivalent to this.guessHandler("guess0", choices[0]);. But we don't do that because then it would be hardcoded and the same at the next iteration.

So now we're calling guessHandler on the instance and sending in "guess0" and choices[0]. The variable id will be assigned the string "guess0" (on the first iteration) and guess will be equal to choices[0] on the first iteration. We would then get the element by id "guess0" and add an event listener to it.


If you still want to figure out how to restart the quiz later, I could potentially assist with that as well. Might I make a recommendation that you review how functions, parameters, and arguments work? I feel like 95% of your confusion lies in what is getting sent to where and where it's assigned. None of these should be new concepts. You've learned about strings, arrays, concatenation, functions, arguments, and parameters. I feel like somewhere in there you got it all jumbled up a bit. Don't worry, it happens to me, too. But when it does, I go back to the basics and make absolutely sure I understand it at the basic level.

I hope at least some of this has been helpful! :sparkles:

Thank you Jennifer Nordell . Wow! That clears things up so much for me. Seriously yes thanks. And you’re right in the beginning functions were very difficult for me. I still remember the espresso explanation. I knew I didn’t fully grasp it. I should have gone over it before moving on. I knew it would come back to bite me in the ass sooner or later. But no, your explanation is very clear, and I will read it over and over again till I make sense of all the code in this app. I’m sorry to say that @Andrew Chalkley explanation aren’t as clear. And yes please. I’m truly stuck on the restart button. I would appreciate your help. @Steven Parker as usual thanks again for always taking the time to respond to my questions.

Steven Parker I didn't want to break it up into separate questions because they all referred to one project. It would be confusing to go to different responses each time I needed to reread the responses, like I'm doing now. I guess the restart button could be a new question though. touche :)

Jennifer Nordell
seal-mask
.a{fill-rule:evenodd;}techdegree
Jennifer Nordell
Treehouse Teacher

Woops! I just saw that you asked about the "restart" button and getting it working. Yes, I think that would be a great "new" question :smiley: