I am making a quiz. I would like to iterate over the different buttons to bring up different questions once I press the buttons. However, since each button has a different id, I am finding it difficult to find a way of changing the id names in the loop. See below for code:
let mybtn1 = document.getElementById("myBtn1")
let questions = [
{
question : "What is an Epidemics?",
choiceA : "CorrectA",
choiceB : "WrongB",
choiceC : "WrongC",
choiceD: "Hello",
correct : "Hello"
},{
question : "What does CSS stand for?",
choiceA : "Wrong",
choiceB : "Correct",
choiceC : "Wrong",
correct : "B"
},{
question : "What does JS stand for?",
choiceA : "Wrong",
choiceB : "Wrong",
choiceC : "Correct",
correct : "C"
}
];
mybtn1.addEventListener("click", pressbtn);
function pressbtn(){
modal.style.display = "block";
questionText.innerHTML = questions[0].question;
answerA.innerHTML = questions[0].choiceA;
answerB.innerHTML = questions[0].choiceB;
answerC.innerHTML = questions[0].choiceC;
answerD.innerHTML = questions[0].choiceD;
}
<ul class="path-one-row">
<li class="grid blue" id="myBtn1"></li>
<li class="grid blue" id="myBtn2"></li>
<li class="grid blue" id="myBtn3"></li>
<li class="grid blue" id="myBtn4"></li>
</ul>
For example, when I click the button with id='mybtn1', it should iterate to give me access to questions[0] and so then I can manipulate the innerHTML. For id='mybtn2', questions[1] and so on. How could I write a loop to help me iterate this?
You can just give the buttons the same class or data-attribute, and you can select them with querySelectorsAll and loop through, and with its index, you can iterate through.
For example all button has the data-question attribute.
Get them like
const questions = document.querySelectorsAll('[data-question]')
And loop through
questions.forEach((index) => {
question.addEventListener("click", () => pressbtn(index));
function pressbtn(index){
modal.style.display = "block";
questionText.innerHTML = questions[index].question;
answerA.innerHTML = questions[index].choiceA;
answerB.innerHTML = questions[index].choiceB;
answerC.innerHTML = questions[index].choiceC;
answerD.innerHTML = questions[index].choiceD;
}
})
Well, there are several ways to make that. Using vanilla javascript you can call a function when clicking a button, pass the id to the function and create the li with that data
<button id="0" click = changeButtons(id)>
<ul id="buttonList>
</ul>
//change buttons
changeButtons (id){
let list =document.getElementbyId(buttonList)
let questions = []
questions[id].forEach(question => {
list.innerHtml += <li><button> question</button> </li>
})
}
note that you have to alter your json to make an array with the questions, you also can use keys to make an array with your questions keys and access to that
Related
I am building a trivia app that loads random questions (from a series of objects I have stored in a Javascript file). Each question has four answers, 3 of them being wrong and 1 right. I am trying to get the possible answers for each question to load into the buttons. Right now all the buttons are loading the first item of the array for each question.
How is this done? I have experimented with forEach and a few other array methods, and I am thinking that the answers must be iterated over and then something with the indexes of each.
<div class="answers-container">
<button id="answers-btn-1" class="answers-btn"></button>
<button id="answers-btn-2" class="answers-btn"></button>
<button id="answers-btn-3" class="answers-btn"></button>
<button id="answers-btn-4" class="answers-btn"></button>
</div>
randomQuestion.answers.forEach(answer => {
answersButton1.innerHTML = answer.text;
answersButton2.innerHTML = answer.text;
answersButton3.innerHTML = answer.text;
answersButton4.innerHTML = answer.text;
});
Also, is there a way to consolidate the code with one answer-btn?
What I understand from your descriptions this could be a possible solution:
randomQuestions.answer.forEach((answer, index) => {
document.getElementById(`answers-btn-${index + 1}`).textContent = answer;
});
Example pure JS to control random answers list and use in buttons:
let answersUsed = [];
let answers = [
'All variables in JavaScript are object data types',
'Netscape is the software company that developed JavaScript',
'isNan function returns true if the argument is not a number',
'JavaScript is a client-side and server-side scripting language',
'Negative Infinitycan be derived by dividing negative number by zero'
];
function getRandomAnswer() {
let answerUsed = answers[Math.floor(Math.random() * answers.length)];
answersUsed.push(answerUsed);
const index = answers.indexOf(answerUsed);
if (index > -1) {
answers.splice(index, 1);
}
return answerUsed;
}
answers.forEach(answer => {
document.getElementById("answers-btn-1").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-2").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-3").innerHTML = getRandomAnswer();
document.getElementById("answers-btn-4").innerHTML = getRandomAnswer();
});
button {
margin: 8px;
display: block;
}
<div class="answers-container">
<button id="answers-btn-1" class="answers-btn"></button>
<button id="answers-btn-2" class="answers-btn"></button>
<button id="answers-btn-3" class="answers-btn"></button>
<button id="answers-btn-4" class="answers-btn"></button>
</div>
You can do this by building a list of options and setting the innerHTML of a select element or build an input[type="radio"] for each answer.
const randomQuestion = {answers: [{text: 'one'},{text: 'two'},{text: 'three'},{text: 'four'}]}
const opts = ['<option disabled>Choose one</option>']
randomQuestion.answers.forEach(answer => {
opts.push(`<option value="${answer.text}">${answer.text}</option>`)
});
const answerSelect = document.querySelector('#answer-select')
answerSelect.innerHTML = opts.join("\n")
answerSelect.size = opts.length // shows all options
answerSelect.value = ""
const radio_opts = []
randomQuestion.answers.forEach(answer => {
radio_opts.push(`<label><input type="radio" name="answerRadio" value="${answer.text}" />${answer.text}</label>`)
});
document.querySelector('#answers-container').innerHTML = radio_opts.join("\n")
<select class="answer-select" name="answer" id="answer-select">
<option>answer</option>
</select>
<div class="answers-container" id="answers-container">
<input type="radio" name="answerRadio">
</div>
Is there a way with JS/JQuery to create an array with a different variable for each of the following specific elements in my page?
<div id#1-hello></div>
<div id#2-hello></div>
...etc
and give them a value depending on the class name attached to that element? (for instance if the class name is count-2 value will be 2)
Right what I'm doing is not really efficient as I'm repeating a lot of my functions, and have to manually add more whenever I want to add new html elements:
var pets = ["Error", "Fish", "Wolf", "Whale", "Zebra", "Ferret"];
var petClass = $('#1-fish').hasClass('petClass')
switch(petClass) {
case 'count-0':
pets[1] = 0;
break;
case 'count-1':
pets[1] = 1;
break;
case 'count-2':
pets[1] = 2;
break;
case 'count-3':
pets[1] = 3;
break;
default:
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="1-fish" class="map-marker count-0"></div>
<div id="2-wolf" class="map-marker count-2"></div>
<div id="3-whale" class="map-marker count-3"></div>
<div id="4-zebra" class="map-marker count-1"></div>
<div id="5-ferret" class="map-marker count-1"></div>
You question is a bit vague. Are you looking for something like this?
var pets = ["Error", "Fish", "Wolf", "Whale", "Zebra", "Ferret"];
var petCounts = {};
pets.each(function (pet) {
var petCountDivs = $('[id$="'+pet+'"]').find('petClass');
petCountDivs.each(function () {
var countClass = $(this).attr("class").split(/\s+/).find(function(maybeCountClass) {
return maybeCountClass.startsWith("count");
}
var petCount = countClass.substring(countClass.lastIndexOf('-'));
if (petCounts[pet]) {
petCounts[pet] += petCount;
} else{
petCounts[pet] = petCount;
}
});
});
This first uses the $= selector to find elements whose 'id' attribute "ends with" the specified petname from the pets array, then uses .find('petClass') on those elements, so that var petCountDivs is a collection of all the elements that are inside pet-named divs that have the petClass class.
Then looping through each of those petCountDivs, it grabs the name of the class that starts with the word "count", and parses the value that comes after the dash ('-'), then either creates a new count object or aggregates to the existing counter that parsed value.
I use WordPress. I have an audio player on my site. When a user clicks the play button on an individual song, it will play the song. The post ID is how the player determines which song to play.
So in the DIV that wraps the button tag, I assign an attribute: data-id which is the post id of the song. My app then grabs the MP3 file that is associated with that post ID. Simple.
My play button tag is essentially this:
<div class="item item-action" data-id="1161">
<button class="btn-playpause"></button>
</div>
The important parts of my player.js file that handles the click event and plays the song is below:
Simulate the play button
// simulate the play btn
$(document).on('click.btn', '.btn-playpause, .btn-queque', function(e){
e.stopPropagation();
var self = $(this),
item = $(this).closest('.item'),
id = item.attr('data-id'),
type = item.data('user-id') ? 'user' : 'post',
play = true;
if(!player){
getItem(id, type).done(function(obj){
if(obj.status == 'success'){
mep.mepPlaylistTracks = obj.tracks;
initPlayer();
player && player.mepSelect(0, true);
}
});
return;
}
if(self.is('.btn-queque')){
play = false;
self.parent().dropdown('toggle');
}
if( self.hasClass('is-playing') ){
self.removeClass('is-playing');
player.pause();
}else{
var index = player.find(id);
if( index !== -1){
var track = player.mepGetCurrentTrack();
if(track && track.id == id && !play) return;
player.mepSelect(index, true);
}else{
getItem(id, type).done(function(obj){
if(obj.status == 'success'){
addToPlay(obj.tracks, play);
}
});
}
}
});
getItem() function
function getItem(id, type){
return $.ajax({
type : "post",
dataType : "json",
url : ajax.ajax_url,
data : {action: "ajax_music", id : id, type: type, nonce: ajax.nonce}
});
}
addToPlay() function
function addToPlay(obj, play){
if(obj.length == 1){
player.mepAdd( obj[0], play );
}else if(obj.length > 1){
if(play){
player.options.mepPlaylistTracks = obj;
player.updatemepList();
player.mepSelect(0, true);
}else{
for(var i=0; i<obj.length; i++){
player.mepAdd( obj[i] );
}
}
}
}
You can see that once I click the play button, depending on a condition, it fires the getItem() function. getItem() takes the data-id attribute defined earlier as the id variable and begins to play the song.
The addToPlay() function will add another song to the playlist if there is already an instance of the player open. And when a user clicks another play button, it will add that new song to the list and begin to play that song.
Is it possible to modify this code so that I can add multiple data-id values to my button code so that my script will recognize there is more than one song id and add those to my playlist, using the addToPlay() function?
I'd like to do something like this
<div class="item item-action" data-id="1161, 1288, 1456">
<button class="btn-playpause"></button>
</div>
The reason I want to do this, is I would like to add a feature that will allow my users to Play All Songs on the current page they're viewing. Some of our pages, like the catalog page, displays dozens of songs that fit a certain criteria and I'd like the option to play all songs on the page.
Can anyone help push me in the right direction?
Thanks.
You could store a JSON encoded array in the data-id tag. Like:
<div class="item item-action" data-id='[1161, 1288, 1456]'>
<button class="btn-playpause"></button>
</div>
Then you can parse the array, and loop over its contents, adding each id to the queue.
See an example of parsing here: https://gist.github.com/charliepark/4266921
Here I present a alternative method.
In your markup, you can set the data-id='[1234] attribute as an encoded array. You can then collect those properties and set them as the data id property on a given element using jQuery as I illustrate here:
let someElement = $('.item');
let setItems = someElement.data('id');
let thisItem = someElement.attr('data-id');
IMPORTANT: the someElement.data('id') returns the same as the someElement.attr('data-id') (except as a string) IF nothing for that element has been set with someElement.data('id',[567,890]); which sets the property id for someElement. So, once set that way
let x = someElement.data('id'); // returns the array 567,890
let org = someElement.attr('data-id'); // still returns the [1234]
This code illustrates:
let someElement = $('.item').first();
let setItems = someElement.data('id');
let thisItemS = someElement.attr('data-id');
// make an array of the string
let thisItem = JSON.parse(thisItemS);
console.log(typeof setItems, setItems, typeof thisItemS, thisItemS, typeof thisItem, thisItem);
someElement.data('id', [567, 890]);
let x = someElement.data('id'); // returns and gets the array 567,890
let org = JSON.parse(someElement.attr('data-id')); // still returns the string [1234] made into an array
// merge with no duplicates, in the other code I used .map()
let z = Array.from(new Set(x.concat(org)));
console.log(x, org, z);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class='item' data-id='[1234]'>me the item</div>
This code show a set of elements using the concepts introduced above plus:
Set some check boxes for selection
Get the values (all)
Get the values (checkbox checked)
You can combine any of this for your original purpose, but you will need to manage that addition of new items values (and subsequently how to remove perhaps) on a given element. You might even add to a <select> element so the user then can pick some to remove perhaps...
function showPicks(choicedata) {
let ul = $('#choices').append('<ul />');
//ul.remove('li');
ul.html('empty');
ul.text('choices:');
$.each(choicedata, function(index, choice) {
let c = $('<li/>').html(choice);
ul.append(c);
});
}
$(function() {
let mydata = $('.item').map(function() {
return $(this).data('id');
}).get();
$('.all-items').data("id", mydata);
showPicks(mydata); //now do what is desired
});
$('item.item-action').filter(':not(".some-items")')
.on('click', '.btn-playpause', function() {
let setItems = $(this).closest('.item').data('id');
let thisItem = $(this).closest('.item').attr('data-id');
// do what you wish here, I show them
showPicks(setItems);
});
$('.some-items').on('click', '.btn-playpause', function(event) {
let mydata = $('.item-select').filter(':checked')
.add(this) // set an additional one from the button
.closest('.item')
.map(function() {
return $(this).data('id');
}).get();
$(event.delegatedTarget).data("id", mydata);
let setItems = $(event.delegatedTarget).data('id');
// the original pick
let thisItem = $(event.delegatedTarget).attr('data-id');
// do what you wish here
showPicks(mydata);
});
.btn-playpause {
height: 2em;
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="item item-action" data-id="[1161]">
<button class="btn-playpause" type="button"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action" data-id="[1163]">
<button class="btn-playpause"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action" data-id="[9961,7744]">
<button class="btn-playpause" type="button"></button>
<input type="checkbox" class="item-select" />
</div>
<div class="item item-action all-items" data-id="[42]">
<button class="btn-playpause" type="button">Play All</button>
</div>
<div class="item item-action some-items" data-id="[95]">
<button class="btn-playpause" type="button">Play selected</button>
</div>
<div id="choices">none</div>
Im trying to create a simple quiz with Javascript. I am struggling to grasp the concept of how to iterate over the values of an array from an object. I eventually want to display a radio button with its value as the choice of answers. If someone could point me in the right direction i would really appreciate it.
Fiddle: http://jsfiddle.net/Renay/eprxgxhu/
Here is my code:
HTML
<h1> General Knowledge Quiz </h1>
<h2 id='questionTitle'> </h2>
<ul id ='selectionList'> </ul>
<p> Click the next button to go to the next question! </p>
<button type="button" id = nextButton> Next </button>
</div>
Javascript
var allQuestions = [{
question: 'What is the capital city of Australia?',
choices: ['Sydney', 'Melbourne', 'Canberra', 'London'],
correctAnswer: 2
},
{
question: 'Who won the 2014 FIFA World Cup?',
choices: ['Brazil', 'England', 'Germany', 'Spain'],
correctAnswer: 2
},
{
question: 'What book series is authored by J.K Rowling?',
choices: ['Game of Thrones', 'Hunger Games', 'Twilight', 'Harry Potter'],
correctAnswer: 3
},
{
question: 'The Eiffel Tower is located in which following country?',
choices: ['Italy', 'France', 'Iceland', 'Mexico'],
correctAnswer: 1
}];
//Reference to tags
var questionTitle = document.getElementById('questionTitle');
var selectionList = document.getElementById('selectionList');
var nextButton = document.getElementById('nextButton');
//Initiating some variables
var i = 0;
var length1 = allQuestions.length;
var correctAnswer = 0;
function populateQuestion() {}
Firstly attach click event to next button and give call to populateQuestion() using counter to iterate through allQuestions array and use i as counter variable.
nextButton.onclick = function() {
/*itterate through questions*/
if(i>allQuestions.length -1){/*go to first when reached last*/
i=0;
}
populateQuestion(i);
i++;
};
Iterate through allQuestions array for question title and choices as:
function populateQuestion(qNum) {
var individualQuestion = allQuestions[i];
questionTitle.innerText = individualQuestion.question;
selectionList.innerHTML = ""; //reset choices list
for(key in individualQuestion.choices){
var radioBtnName = "question"+i+"_choice";
var choiceText = individualQuestion.choices[key];
selectionList.appendChild(createLi(radioBtnName,choiceText));
}
}
Write dynamic li and radio button creation function as:
function createLi(name, choiceText) {
var e = document.createElement('li');
var radioHtml = '<input type="radio" name="' + name + '"';
radioHtml += '/>';
radioHtml += choiceText;
e.innerHTML = radioHtml;
return e;
}
Please refer to this fiddle for same.
You need to associate an onClick event with your button to call the relevant part of the JavaScript. Go through the example here
On another note, using JavaScript for a quiz might not be a good idea as one can see the answers using view-source. I would suggest using PHP to fetch results from a database.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to figure out the best way to build a questionnaire. See below.
http://cl.ly/image/1W2M3J2z2q2E
http://cl.ly/image/2m461g200b0X
This is what I've got in my code, and it works just fine but as you can see, it gets incredibly long after just two questions. What is the best way to condense this code, so that I do not repeat myself so many times.
// find all anchor tag and prevent default behavior
$('.questions').find('a').on('click', function(e){
e.preventDefault();
});
var ques1 = $('#question1'),
q1 = $('.question1'),
q1True = $('.question1-true').hide(),
q1False = $('.question1-false').hide();
var ques2 = $('#question2'),
q2 = $('.question2').hide(),
q2True = $('.question2-true').hide(),
q2False = $('.question2-false').hide();
(function () {
// click button false
$('#question1 .btn-false').on('click', function(){
q1.hide();
q1True.fadeIn();
});
// click button true
$('#question1 .btn-true').on('click', function(){
q1.hide();
q1False.fadeIn();
});
// click previous button
$('#question1 .prev').on('click', function(){
q1True.hide();
q1False.hide();
q1.show();
});
// click next button
$('#question1 .next').on('click', function(){
ques1.hide();
q2.show();
}); //end question1
// begin question 2
$('#question2 .btn-false').on('click', function(){
ques2.show();
q2.hide();
q2True.show();
});
$('#question2 .btn-true').on('click', function(){
ques2.show();
q2.hide();
q2False.show();
});
})();
Just to give you an idea:
LIVE DEMO
HTML:
<div id="QA">
<div id="qDIV">
<h2></h2>
<button>False</button>
<button>True</button>
</div>
<div id="response">
<p></p>
<button id="prev">Back</button>
<button id="next">Next</button>
<button id="score">Score</button>
</div>
</div>
<pre></pre>
Let's now create an Array of object literals to store data:
var questionnaire = [
{
"question" : "The Earth is round.",
"response" : "The Earth is round!",
"correct" : 1 // 0=False, 1=True
},
{
"question" : "The 'cravat' is originally from France.",
"response" : "The 'cravat' is from Croatia!",
"correct" : 0
},
{
"question" : "Is Java == JavaScript?",
"response" : "It's a different language.",
"correct" : 0
} // Add comma and more objects.
];
This way we can always keep track of the values and inject at every stage an user answer into our current question object.
var $qDIV = $('#qDIV'),
$rDIV = $('#response'),
$qH2 = $("h2", $qDIV),
$answer = $("button", $qDIV),
$response = $("p", $rDIV),
tot = questionnaire.length,
c = 0; // Current Q array counter
function QandA( idx ){
$qDIV.fadeTo(600,1);
$rDIV.hide();
var currQ = questionnaire[c]; // The Object literal from Array
var isCorrect = currQ.correct; // 0 or 1?
var answerIsCorrect = idx==isCorrect; // (compare values) Returns boolean
var resp = answerIsCorrect ? "Great!" : "Wrong!";
currQ.answer = idx; // Put user answer into object (0 or 1)
$qH2.text( (c+1) +'. '+ currQ.question );
$response.text( resp +' '+ currQ.response );
}
QandA();
$answer.click(function(){
var idx = $answer.index(this); // 0 or 1 (get button index)
QandA( idx );
$rDIV.fadeTo(600,1);
$qDIV.hide();
console.log( JSON.stringify(questionnaire, null, 2) ); // TEST ONLY
});
$('#prev, #next').click(function(){
c = this.id=='next' ? ++c : c ; // advance or repeat Question
QandA();
$('#next').toggle(c<tot-1);
$('#score').toggle(c>=tot-1);
});
$('#score').click(function(){
$('pre').text( JSON.stringify(questionnaire, null, 2) ); // TEST
c = 0; // reset questionnary to first question
QandA(); // Restart
});
Previous answer:
LIVE DEMO
having this trivial HTML:
<div id="QA">
<h2></h2>
<span id="buttons"></span>
<p>Points : <span>0</span></p>
</div>
Let's create an array of object literals like:
var questionnaire = [
{
"question" : "The earth is...",
"valid" : 1, // indicates the correct array number, use 0, 1...
"buttons" : ["A cube", "Round"],
"answers" : [ "Ohh, c'mon...", "You got it! It's round!"]
},
{
"question" : "The Cravat is originally from:",
"valid" : 0,
"buttons" : ["Croatia", "France", "Germany"],
"answers" : [ "Great", "Wrong, it's from Croatia!", "Wrong... Sorry"]
},
{
"question" : "Is Java == JavaScript?",
"valid" : 0,
"buttons" : ["False", "True"],
"answers" : ["Exatcly!", "Ohh, c'mon..."]
} // add comma and more Object literals...
];
In the above you can create as many possible buttons and answers you want. jQuery will create the buttons out of the needed object Array. Than you set a valid pointer to tell the questionnaire logic which of the answers index is the correct one using 0, 1, 2....
After jQ creates our buttons, on a button click you can retrieve it's index and target the needed answer out of your object literal, and to determine the points see if the clicked button index matches your valid value.
As you can see you can advance your questions by incrementing a counter variable after every button click (we'll call qc):
var $qa = $('#QA'),
$question = $("h2", $qa),
$buttons = $("#buttons", $qa),
$points = $("p>span",$qa),
questionnaireLength = questionnaire.length, // How many Q?
qc = 0, // Current Question counter
points = 0; // Current points
function QandA(){
var quest = questionnaire[qc],
question = quest.question,
validIdx = quest.valid,
btns = quest.buttons,
answer = quest.answers;
$question.text( question );
if(qc >= questionnaireLength){
return alert("game over");
}
// generate buttons with text:
$buttons.empty();
for(var i=0; i<btns.length; i++){
$buttons.append("<button>"+ btns[i] +"</button>");
}
// Retrieve generated buttons
var $btn = $("button", $buttons);
// Assign click
$btn.one('click', function(){
var idx = $btn.index(this); // get button index
alert("(valid idx is: "+ validIdx +" Clicked button idx: "+ idx +")");
alert("Game says: "+ answer[idx] );
points += (idx === parseInt(validIdx, 10) ? 5 : -5);
$points.text( points );
// Next question
qc++; QandA(); // increment question counter and set new game
});
}
QandA(); // Start game