How to go about reusing my js code without just copying it and changing the names of variables? I want to add more questions but reuse the same code? This is a simple web test/quiz.
CURRENT CODE CurrentUI
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DOM STUFF</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1 id="counter-display">Total:</h1>
<div id="questionBox">
<p id="question">Q1: What is My favorite Food?</p>
<p>
<input type="radio" name="answer" value="Chicken" /> Chicken
<input type="radio" name="answer" value="Pork" /> Pork
<input type="radio" name="answer" value="Seafood" /> Seafood
<input type="radio" name="answer" value="Junkfood" /> Junfoods
<input type="radio" name="answer" value="Vegetables" /> Vegetables
</p>
<p>
<button id="Submit">Submit</button>
</p>
</div>
<script src="dom.js"></script>
</body>
</html>
JS
let Submit = document.getElementById('Submit');
let counterDisplayElem = document.getElementById('counter-display');
let question = document.getElementById('question');
let correctAns = 'Pork';
let total = '0';
//submit q1 on click, calling scoreQuestion
Submit.addEventListener('click', () => {
scoreQuestion();
});
//score q1
function scoreQuestion(params) {
let answerArray = document.getElementsByName('answer');
answerArray.forEach((answer) => {
if (answer.checked) {
if(answer.checked && answer.value ==correctAns){
total
counterDisplayElem.innerHTML = total;
Submit.style.display = 'none'; //hide submit on correct entry
} else {
alert("Incorrect");
question.innerHTML = " Epic Fail";
}
}
})
}
ATTEMPTED SOLUTION MY GOAL Solution UI
When I try to add more questions I must add more imports and variables as well. Is there an idea I am missing or is this just the way it is with web development?
let question1 = document.getElementById('question1');
let question2 = document.getElementById('question2');
let question3 = document.getElementById('question3');
let Submit1 = document.getElementById('Submit1');
let Submit2 = document.getElementById('Submit2');
let Submit3 = document.getElementById('Submit3');
//submit q1
Submit1.addEventListener('click', () => {
scoreQuestion();
});
//score q1
function scoreQuestion1(params) {}
//submit q2
Submit2.addEventListener('click', () => {
scoreQuestion3();
});
//score q2
function scoreQuestion2(params) {}
//submit q3
Submit3.addEventListener('click', () => {
scoreQuestion3();
});
//score q3
function scoreQuestion3(params) {}
HTML
<div id="questionBox1">
<p id="question1">Q1: What is My favorite Food?</p>
<p>
<input type="radio" name="answer1" value="Chicken" /> Chicken
<input type="radio" name="answer1" value="Pork" /> Pork
<input type="radio" name="answer1" value="Seafood" /> Seafood
<input type="radio" name="answer1" value="Junkfood" /> Junfoods
<input type="radio" name="answer1" value="Vegetables" /> Vegetables
</p>
<p>
<button id="Submit1">Submit</button>
</p>
</div>
<div id="questionBox2">
<p id="question2">Q1: What is My favorite ETC?</p>
<p>
<input type="radio" name="answer2" value="Chicken" /> Chicken
<input type="radio" name="answer2" value="Pork" /> Pork
<input type="radio" name="answer2" value="Seafood" /> Seafood
<input type="radio" name="answer2" value="Junkfood" /> Junfoods
<input type="radio" name="answer2" value="Vegetables" /> Vegetables
</p>
<p>
<button id="Submit2">Submit</button>
</p>
</div>
<div id="questionBox3">
<p id="question3">Q1: What is My favorite ETC?</p>
<p>
<input type="radio" name="answer3" value="Chicken" /> Chicken
<input type="radio" name="answer3" value="Pork" /> Pork
<input type="radio" name="answer3" value="Seafood" /> Seafood
<input type="radio" name="answer3" value="Junkfood" /> Junfoods
<input type="radio" name="answer3" value="Vegetables" /> Vegetables
</p>
<p>
<button id="Submit3">Submit</button>
</p>
</div>
Just rewriting the code and changing the variable questionbox 1 2 and 3 and answer 1 2 and 3 and submit 1 2 and 3 feels wrong and disgusting and I am sure there is a simpler and easier way to do this. Makes me feel dirty lol.
Any input is appreciated.
B
CodePudding user response:
Here's a simple use case for your function through a loop. I put it in the click handler itself to make it easier to access the elements. If you need this function separately, you will have to pass the elements through parameters.
Here I changed the id to class, and added a data-set on the radio elements to mark the correct answers. If you need to hide them, you can add an array with responses in the sequence of HTML elements and notice the data-set for the correct[index] in js function.
let counterDisplayElem = document.getElementById('counter-display');
let total = 0;
const questionList = document.querySelectorAll('.questionBox');
questionList.forEach(function(item) {
const btnSubmit = item.querySelector('.submit');
const question = item.querySelector('.question');
btnSubmit.addEventListener('click', function() {
let answerArray = document.getElementsByName('answer');
answerArray.forEach((answer) => {
if (answer.checked) {
if(answer.checked && answer.dataset.correct === 'true'){
total ;
counterDisplayElem.innerHTML = 'Total: ' total;
btnSubmit.style.display = 'none';
} else {
alert("Incorrect");
question.innerHTML = " Epic Fail";
}
}
});
});
});
<h1 id="counter-display">Total:</h1>
<div class="questionBox">
<p class="question">Q1: What is My favorite Food?</p>
<p>
<input type="radio" name="answer" value="Chicken" /> Chicken
<input type="radio" name="answer" value="Pork" data-correct="true" /> Pork
<input type="radio" name="answer" value="Seafood" /> Seafood
<input type="radio" name="answer" value="Junkfood" /> Junfoods
<input type="radio" name="answer" value="Vegetables" /> Vegetables
</p>
<p>
<button class="submit">Submit</button>
</p>
</div>
<div class="questionBox">
<p class="question">Q2: What is My favorite Food?</p>
<p>
<input type="radio" name="answer" value="Chicken" data-correct="true" /> Chicken
<input type="radio" name="answer" value="Pork" /> Pork
<input type="radio" name="answer" value="Seafood" /> Seafood
<input type="radio" name="answer" value="Junkfood" /> Junfoods
<input type="radio" name="answer" value="Vegetables" /> Vegetables
</p>
<p>
<button class="submit">Submit</button>
</p>
</div>
<div class="questionBox">
<p class="question">Q3: What is My favorite Food?</p>
<p>
<input type="radio" name="answer" value="Chicken" /> Chicken
<input type="radio" name="answer" value="Pork" /> Pork
<input type="radio" name="answer" value="Seafood" /> Seafood
<input type="radio" name="answer" value="Junkfood" /> Junfoods
<input type="radio" name="answer" value="Vegetables" data-correct="true" /> Vegetables
</p>
<p>
<button class="submit">Submit</button>
</p>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
Yes copy-paste-edit is wrong. This code does not scale. Ideally the questions' html is created from an array of question objects using Javascript. Designing a "Question" object and an array will drastically simplify passing data to html construction, event handling, and keeping an up to date set of questions.
All question html is the same so write a single function to create the html, passing in a question object.
All submit buttons are likewise similar so a single function for building that also.
To add a question you should be able to just add it to the questions array. Same for deleting or changing a question.
Use only one event handler. As all questions are handled the same and they all add to the same total.
Specific frameworks are not required to do this.
Create an array of Question objects with needed properties: "id", "question", "name", "correctAnswer". Maybe "yourAnswer" also.
event handler function; pass all the particulars of that question as arguments to the event handler call. Passing all this as a question object will probably make referencing easier.
Don't call the button "submit" because "submit" has a particular, well known, idiomatic meaning in html/javascript data entry. It means to pass/process the entire form and there is a special built-in button type for this.
CodePudding user response:
Use event.target to detect wich element is selected then you click on input /or use JQuery :
const Submit = $('#Submit');
const counterDisplayElem = $('#counter-display');
Submit.change(function() {
if(this.checked && this.value == correctAns) {
scoreQuestion(this.value)
} else {
alert("Incorrect");
question.innerHTML = " Epic Fail";
}
});
function scoreQuestion(params) {
total
alert('Correct->' params);
counterDisplayElem.innerHTML = total;
Submit.style.display = 'none';
}
CodePudding user response:
You need something like this. This is far from ideal code and its more like example how you might achieve reusability and avoid duplication, but after you grasp a bit of idea, you can deep dive in details and possibilities. https://jsfiddle.net/8rhjL4gw/59/
<div id="questions">
</div>
<script>
const list = document.getElementById('questions');
const data =[{
question: 'My favourite food is?',
answers: ['chicken', 'pork']
},
{
question: 'My favourite dring is?',
answers: ['water', 'juice', 'vodka']
}];
data.forEach((x,index)=> {
const question = document.createElement('p');
question.innerText = x.question;
list.appendChild(question);
x.answers.forEach(answer => {
const radioInput = document.createElement('input');
radioInput.setAttribute('type', 'radio');
radioInput.setAttribute('name', 'answer' index);
radioInput.setAttribute('value', answer);
radioInput.innerText = answer;
list.appendChild(radioInput);
var lab = document.createElement("label");
lab.textContent =answer;
list.appendChild(lab);
})
})
</script>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>