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
Jeremy Castanza
12,081 PointsHow to Extend the Quiz - Add support for multiple choices.
Hi,
I'm interested in extending the quiz to allow each question to have 2 or more choices. Upon experimenting with the completed project, I noticed that the first item in the questions array must have the same number of questions as buttons. If there are three or more choices on the first array item, the DOM doesn't dynamically generate buttons or display the choices.
I'd like to implement this functionality to allow the number of buttons to correspond with any number of choices on the page. If anyone has any suggestions on how to add some dynamic button functionality for each question, I'm interested in a proposed solution or at least a good reference point about where to begin implementing it.
Andrew Chalkley, this might be a good extra credit feature for this video. I'm curious as to which JS file do you think would make sense for this functionality. Also, is this something that you'd recommend doing in vanilla JS or using jQuery?
Thanks, Jeremy
3 Answers
Andrew Chalkley
Treehouse Guest TeacherYou can use either. It's a matter of preference. If you can do it in vanilla JS, great. That saves the extra download of the jQuery library. Either way it's fine.
You can create elements with document.createElement in plain old JavaScript or $('<button />') in jQuery.
Jeremy Castanza
12,081 PointsAndrew Chalkley , I developed a solution that seems to work. I was wondering if you could provide a code review for the method and/or any improvements that you'd make. I feel like it could be more DRY, but on the upside it works. As mentioned previously, this may make a cool extra credit project in the teacher's notes for the Quiz project. Thanks!
All the additions were done in Quiz_UI.js
I updated the displayChoices method to include a call to the removeChoices method:
displayChoices: function () {
var choices = quiz.getCurrentQuestion().choices;
var buttons = document.getElementsByTagName('button');
for(var i = 0; i < choices.length; i++) {
this.populateIdWithHTML("choice" + i, choices[i]);
this.guessHandler("guess" + i, choices[i]);
}
this.removeChoices();
},
From there, I built a method from scratch called removeChoices. This method is basically meant to help remove buttons and list items. This way, the Quiz UI adapts to questions that may have more choices than others.
removeChoices: function () {
var buttons = document.getElementsByTagName('button');
var listItems = document.getElementsByTagName('li');
var numOfChoices = quiz.getCurrentQuestion().choices.length;;
var numOfButtons = buttons.length;
// Remove old list items/buttons, if current question has less than previous
if (numOfChoices < numOfButtons) {
var btnDifference = numOfButtons - numOfChoices;
for(var i = 0; i < btnDifference ; i++) {
var elementID = numOfButtons - 1;
var oldButton = buttons[elementID - i];
var oldListItem = listItems[elementID - i];
oldButton.parentNode.removeChild(oldButton);
oldListItem.parentNode.removeChild(oldListItem);
}
}
},
Andrew Chalkley
Treehouse Guest TeacherThat's awesome. I like how you separated your code. It's very readable.
Here's something you could do...
- Create a function called
createElement()that takes in a string oftagNameand returns the newly created element. - Set a variable to the expression
elementID - ias something understandable. - You could also create a function called
removeChild()that removes the child element from theparentNode.
Jeremy Castanza
12,081 PointsHey Andrew Chalkley, I actually had to rework what I provided to you. My method was useful for only one condition - When the number of buttons was greater than the choices in the array for that question. So... I refactored a bit and created a new method altogether. So far, it seems to work for any number of choices for a given question.
Here's what I ended up doing:
Updated displayNext method to include new Method updateButtons():
displayNext: function () {
if (quiz.hasEnded()) {
this.displayScore();
} else {
this.displayQuestion();
this.updateButtons();
this.displayChoices();
this.displayProgress();
}
},
From there, I created a pretty heavy method called updateButtons:
updateButtons: function () {
var choices = quiz.getCurrentQuestion().choices;
var buttons = document.getElementsByTagName('button');
var listItems = document.getElementsByTagName('li');
var numOfChoices = quiz.getCurrentQuestion().choices.length;;
var numOfButtons = buttons.length;
// Remove old choices/buttons, if current question has less
if (numOfChoices < numOfButtons) {
var btnDifference = numOfButtons - numOfChoices;
for(var i = 0; i < btnDifference ; i++) {
var elementID = numOfButtons - 1;
var oldButton = buttons[elementID - i];
var oldListItem = listItems[elementID - i];
oldButton.parentNode.removeChild(oldButton);
oldListItem.parentNode.removeChild(oldListItem);
}
} else if (numOfChoices > numOfButtons) {
// Calculate difference to determine how many buttons to update
var btnDifference = numOfChoices - numOfButtons;
// Find current choice index location
var currentIndex = numOfChoices - btnDifference - 1;
for(var i = 0; i < btnDifference ; i++) {
currentIndex ++;
// Create empty DOM elements
var newListItem = document.createElement("li");
var newButton = document.createElement("button");
var newButtonText = document.createTextNode("Select Answer");
// Set attributes and append text
newButton.setAttribute("id", "guess" + currentIndex);
newButton.setAttribute("class", "btn--default");
newButton.appendChild(newButtonText);
newListItem.setAttribute("id", "choice" + currentIndex);
// DOM reference point
var container = document.getElementById("choice-container");
// Add to container
container.appendChild(newListItem);
container.appendChild(newButton);
this.populateIdWithHTML("choice" + i, choices[i]);
this.guessHandler("guess" + i, choices[i]);
}
} else {
return true;
}
},
There's one thing that's really bothering me and I don't know if this really matters or not. I've noticed that I'm calling the same variables in different methods. When this starts happening, is it best practice to move them out of their individual methods and into the global namespace?
I'm also curious if you think there's a much shorter or more efficient way to refactor the updateButtons method.
Thanks!