const randomSort = arr => arr.sort(() => 0.5 - Math.random());
const mod = (n, m) => ((n % m) + m) % m;
const bump = (count, index, amount) => mod(index + amount, count);
// Handlebars helpers
Handlebars.registerHelper({
ifEquals: function(arg1, arg2, options) {
return arg1 === arg2 ? options.fn(this) : options.inverse(this);
},
randomEach: function(array, opts) {
if (opts.data) data = Handlebars.createFrame(opts.data);
return randomSort(array).map((e, i) => {
if (data) data.index = i;
return opts.fn(e, { data });
}).join('');
}
});
const compileTemplate = (selector) =>
Handlebars.compile(document.querySelector(selector).innerHTML);
const questions = [{
prompt: "Which fruit is yellow?",
answers: [ "Apple", "Banana", "Cantaloupe", "Date" ],
answer: "Banana"
}, {
prompt: "Which vegetable is red?",
answers: [ "Carrot", "Pea", "Potato", "Tomato" ],
answer: "Tomato"
}];
// Buttons
const prevBtn = document.querySelector('#controls > .prev-btn');
const nextBtn = document.querySelector('#controls > .next-btn');
const showBtn = document.querySelector('#controls > .show-btn');
let currQuestion = 0;
let answers = {};
const main = () => {
rerender();
prevBtn.addEventListener('click', handlePrev);
nextBtn.addEventListener('click', handleNext);
showBtn.addEventListener('click', handleShow);
};
const updateAnswers = (button) => {
const form = button.closest('form');
const value = form.elements.answer.value;
answers[currQuestion] = value;
}
// Templates
const questionTemplate = compileTemplate('#question-template');
const infoTemplate = compileTemplate('#info-template');
const answersTemplate = compileTemplate('#answers-template');
// Rendering contexts
const questionEl = document.querySelector('#question');
const infoEl = document.querySelector('#info');
const answersEl = document.querySelector('#answers');
const navigateQuestion = (amount) => {
currQuestion = bump(questions.length, currQuestion, amount);
};
const handlePrev = () => {
navigateQuestion(-1);
rerender();
};
const handleNext = () => {
navigateQuestion(-1);
rerender();
};
const handleShow = () => {
const answerList = questions.map((question, index) => answers[index]);
answersEl.innerHTML = answersTemplate(answerList);
};
const renderQuestion = (question) => {
questionEl.innerHTML = questionTemplate(question);
infoEl.innerHTML = infoTemplate({
page: currQuestion + 1,
count: questions.length
});
};
const rerender = () =>
renderQuestion(questions[currQuestion]);
main();
.answer-field {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
<script id="question-template" type="text/x-handlebars-template">
<h2>{{prompt}}</h2>
<form onsubmit="return false">
{{#randomEach answers}}
<div class="answer-field">
<input
type="radio"
id="answer-{{@index}}"
name="answer"
value="{{.}}"
{{#ifEquals . ../answer}}checked{{/ifEquals}}
>
<label for="answer-{{@index}}">{{.}}</label>
</div>
{{/randomEach}}
<br />
<button onclick="updateAnswers(this)">Submit</button>
</form>
</script>
<script id="info-template" type="text/x-handlebars-template">
<p>Question {{page}} of {{count}}</p>
</script>
<script id="answers-template" type="text/x-handlebars-template">
<ol>
{{#each .}}
<li>{{.}}</li>
{{/each}}
</ol>
</script>
<div id="question"></div>
<div id="info"></div>
<div id="controls">
<button class="prev-btn">Prev</button>
<button class="show-btn">Show Answers</button>
<button class="next-btn">Next</button>
</div>
<h2>Submitted Answers</h2>
<div id="answers"></div>