Reputation:
I have a 3 questions quiz I've created for exercise. The quiz itself works, but I want to improve it a bit (see below). The quiz is made up of the following code:
let result = 0;
let right = ()=>{
result += 33.3;
};
let wrong = ()=>{
result -= 33.3;
};
let finish = ()=>{
totalScore = result;
if (totalScore < 0) {
totalScore = 0;
}
alert(Math.ceil(totalScore));
}
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" onclick="right()">Yes</input>
<input type="radio" name="g1" onclick="wrong()">No</input>
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" onclick="wrong()">Yes</input>
<input type="radio" name="g2" onclick="right()">No</input>
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g3" onclick="right()">Yes</input>
<input type="radio" name="g3" onclick="wrong()">No</input>
</div>
<br>
<input type="button" value="finish" onclick="finish()"></input>
</form>
I try time and again to figure out how make the points calculation automatic, instead me changing each time like result += 50
(for 2 questions) or result +=33.3
(for 3 questions) as it would be more efficient, but I have failed so far.
I don't know what to try for that or what to search for that. I can't see how this should be written basically.
Maybe an answer should be based upon dividing 100 by the number of questions, based on number of label
tags in the form (let labelCount = document.querySelectorAll('#quiz label').length;
), and than compare with right and wrong answers.
But I have no idea how to integrate and process that data with the right()
and wrong()
functions.
What approach will you take to auto calculate the totalScore
?
Please see George's answer, and then, my answer.
Upvotes: 0
Views: 1277
Reputation:
Based on George's answer and my additions, here is a fully working example:
<!DOCTYPE html>
<html>
<body>
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" onclick="right()" />Yes
<input type="radio" name="g1" onclick="wrong()" />No
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" onclick="wrong()">Yes
<input type="radio" name="g2" onclick="right()">No
</div>
<div>
<label>Q3 - Z?</label>
<input type="radio" name="g3" onclick="right()">Yes
<input type="radio" name="g3" onclick="wrong()">No
</div>
<!-- -->
<div>
<input type="button" value="finish" onclick="finish()">
</div>
</form>
<script>
let result = 0;
let labelCount = document.querySelectorAll('#quiz label').length;
let questionValue = 100 / labelCount;
let right = ()=>{
result += questionValue;
};
let wrong = ()=>{
result -= questionValue;
};
let finish = ()=>{
let labelCount = document.querySelectorAll('#quiz label').length;
let checkedButtonsCount = document.querySelectorAll('#quiz :checked').length;
if (labelCount !== checkedButtonsCount) {
alert("At least one group is blank.");
}
if (result < 0) {
result = 0;
}
if (result > 100) {
result = 100;
}
return alert(Math.ceil(result));
};
</script>
</body>
</html>
In this example there isn't the problem I had with George's version (see comments). I've also added a check to see if all radio buttons are clicked, and a return for the alert.
Upvotes: 0
Reputation: 68393
Let
with right
and wrong
is creating local scope of result
and not using the result's value global to it at the time of execution of right
and wrong
function.
You need to use var right
and var wrong
Demo
let result = 0;
var right = ()=>{ //see the change here. `let` is replaced with `var`
result += 33.3;
};
var wrong = ()=>{ //see the change here. `let` is replaced with `var`
result -= 33.3;
};
let finish = ()=>{
totalScore = result;
if (totalScore < 0) {
totalScore = 0;
}
console.log(Math.ceil(totalScore));
}
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" onclick="right()">Yes</input>
<input type="radio" name="g1" onclick="wrong()">No</input>
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" onclick="wrong()">Yes</input>
<input type="radio" name="g2" onclick="right()">No</input>
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g3" onclick="right()">Yes</input>
<input type="radio" name="g3" onclick="wrong()">No</input>
</div>
<br>
<input type="button" value="finish" onclick="finish()"></input>
</form>
I try time and again to figure out how make the points calculation automatic, instead me changing each time like result += 50 (for 2 questions) or result +=33.3 (for 3 questions) as it would be more efficient, but I have failed so far.
You can follow this approach
Assign the data-isCorrect
value to the radio button itself.
Remove the onclick
attribute and add a click event by iterating all the radio buttons.
Demo with 4 questions
let result = 0;
var radios = document.querySelectorAll( "input[type='radio']" );
[].slice.call( radios ).forEach( function( element ){
element.addEventListener( "click", function(){
var isCorrect = this.getAttribute( "data-isCorrect" ) == "true";
result += isCorrect ? 33.3 : -33.3;
});
});
let finish = ()=>{
totalScore = result;
if (totalScore < 0) {
totalScore = 0;
}
console.log(Math.ceil(totalScore));
}
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" data-isCorrect="true">Yes</input>
<input type="radio" name="g1" data-isCorrect="false">No</input>
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" data-isCorrect="false">Yes</input>
<input type="radio" name="g2" data-isCorrect="true">No</input>
</div>
<div>
<label>Q3 - Y?</label>
<input type="radio" name="g3" data-isCorrect="true">Yes</input>
<input type="radio" name="g3" data-isCorrect="false">No</input>
</div>
<div>
<label>Q4 - Y?</label>
<input type="radio" name="g3" data-isCorrect="true">Yes</input>
<input type="radio" name="g3" data-isCorrect="false">No</input>
</div>
<br>
<input type="button" value="finish" onclick="finish()">
</form>
Upvotes: 0
Reputation: 6739
You are right in using let labelCount = document.querySelectorAll('#quiz label').length;
to get the amount of labels and then doing 100/labelCount
. All you need to do then is store that value and replace 33.3
with that value, like below
Three Questions Example
let result = 0;
let labelCount = document.querySelectorAll('#quiz label').length;
let questionValue = 100 / labelCount;
let right = () => {
result += questionValue;
};
let wrong = () => {
result -= questionValue;
};
let finish = () => {
totalScore = result;
if (totalScore < 0) {
totalScore = 0;
}
alert(Math.ceil(totalScore));
}
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" onclick="right()" />Yes
<input type="radio" name="g1" onclick="wrong()" />No
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" onclick="wrong()">Yes
<input type="radio" name="g2" onclick="right()">No
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g3" onclick="right()">Yes
<input type="radio" name="g3" onclick="wrong()">No
</div>
<br>
<input type="button" value="finish" onclick="finish()">
</form>
Four Questions Example
let result = 0;
let labelCount = document.querySelectorAll('#quiz label').length;
let questionValue = 100 / labelCount;
let right = () => {
result += questionValue;
};
let wrong = () => {
result -= questionValue;
};
let finish = () => {
totalScore = result;
if (totalScore < 0) {
totalScore = 0;
}
alert(Math.ceil(totalScore));
}
<form id="quiz">
<div>
<label>Q1 - X?</label>
<input type="radio" name="g1" onclick="right()" />Yes
<input type="radio" name="g1" onclick="wrong()" />No
</div>
<div>
<label>Q2 - Y?</label>
<input type="radio" name="g2" onclick="wrong()">Yes
<input type="radio" name="g2" onclick="right()">No
</div>
<div>
<label>Q3 - Y?</label>
<input type="radio" name="g3" onclick="right()">Yes
<input type="radio" name="g3" onclick="wrong()">No
</div>
<div>
<label>Q4 - Y?</label>
<input type="radio" name="g4" onclick="right()">Yes
<input type="radio" name="g4" onclick="wrong()">No
</div>
<br>
<input type="button" value="finish" onclick="finish()">
</form>
Upvotes: 3