-
Notifications
You must be signed in to change notification settings - Fork 1
/
quiz.js
112 lines (100 loc) · 4.13 KB
/
quiz.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* @copyright [email protected]
*/
class Quiz {
/**
* divId - id of div element where to put parsed quiz
* jsonPath - path for .json file containing questions
* answerClass - specifies styling class for answers
* questionClass - specifies styling class for questions
* labelClass - specifies styling class for each option in answers
* correctAnswerClass - styling class for correct answers
* wrongAnswerClass - styling class for wrong answers
* explanationClass - styling class for explanation text
* submitButtonId - id of a button for quiz submission
* @param {Object} - an object of type JSON specifying class names and ids of quiz
*/
constructor({divId, jsonPath, answerClass, questionClass, labelClass,
correctAnswerClass, wrongAnswerClass, explanationClass, submitButtonId}) {
this.quiz = [];
this.quizData = null;
this.quizDataPath = jsonPath;
this.quizContainer = document.getElementById(divId);
this.answerClass = answerClass;
this.questionClass = questionClass;
this.labelClass = labelClass;
this.correctAnswerClass = correctAnswerClass;
this.wrongAnswerClass = wrongAnswerClass;
this.explanationClass = explanationClass;
this.submitButton = document.getElementById(submitButtonId);
}
/**
* Loads json from file and builds quiz string containing html elements.
* @returns promise
*/
parseQuizFromJson = () => {
return new Promise((resolve, reject) => {
fetch(this.quizDataPath)
.then(response => response.json())
.then(data => this.quizData = data.quizData)
.then(() => this.buildHTMLQuiz())
.then(() => resolve())
.catch(err => reject());
})
}
/**
* Appends quiz string containing html elements to quiz container
*/
displayHTMLQuiz = () => {
this.quizContainer.innerHTML = this.quiz.join('');
}
/**
* Builds a string containing html elements that are parsed from input JSON file
*/
buildHTMLQuiz = () => {
this.quizData.forEach(
(question, index) => {
let options = [];
for (let option in question.answers) {
options.push(
`<label class="${this.labelClass}">
<input type="radio" name="q${index}" value="${option}"/>
${question.answers[option]}
</label>`
);
}
this.quiz.push(
`<div>
<div class="${this.questionClass}"> ${question.question} </div>
<div class="${this.answerClass}"> ${options.join('')} </div>
<div class="${this.explanationClass}">${question.explanation}</div>
</div>`
);
}
);
this.submitButton.addEventListener('click', this.checkQuizAnswers);
}
/**
* Evaluates all parsed answers on sumbit button click
*/
checkQuizAnswers = () => {
let answerContainers = this.quizContainer.querySelectorAll(`.${this.answerClass}`);
let numCorrect = 0;
this.quizData.forEach(
(question, index) => {
let answerContainer = answerContainers[index];
const selector = `input[name=q${index}]:checked`;
const userAnswer = (answerContainer.querySelector(selector) || {}).value;
if (userAnswer === question.correctAnswer) {
numCorrect++;
answerContainers[index].classList.add(this.correctAnswerClass);
answerContainers[index].classList.remove(this.wrongAnswerClass);
} else {
answerContainers[index].classList.remove(this.correctAnswerClass);
answerContainers[index].classList.add(this.wrongAnswerClass);
}
}
);
document.getElementById("results").innerHTML = `${numCorrect} out of ${this.quizData.length}`;
}
}