We continue from Part 3 of our Quiz app. This would be the last part
1. Retrieve the Total Questions
Once the player has gotten to the last question, we simply end the quiz and show the score. To do this we need to compare the current index with the total questions. However, the total questions is in the child component. So we need to receive it in the parent component. Again, we use EventEmitter.
In the Question component
@Output() totalQuestions = new EventEmitter<number>();
In the, ngOnInit() method,
this.totalQuestions.emit(this.questions.length);
In the Quiz component
getTotalQuestions(totalQuestions: number) { this.totalQuestions = totalQuestions; }
The Quiz html template would now look like this:
<app-question [questionIndex]="currentIndex" (answers) ="receiveAnswers($event)" (totalQuestions)="getTotalQuestions($event)" > </app-question>
2. Detect End of Quiz
This is very easy. In the goNext() function, check if the current index equals the total questions. If so, call a function endQuiz() to end the quiz. Also, this check should be done after the index is incremented and the score is updated. In this way, the index is now 1 more than the max index, and since it is zero based, it now equals the total questions.
The goNext() now becomes:
goNext() { this.currentIndex++; this.updateScore(); if (this.currentIndex === this.totalQuestions){ this.endQuiz(); } }
For now, add this function:
endQuiz(){ this.quizOver = true; alert('Quiz Over! Score is ' + this.score + '/ ' + this.totalQuestions); }
We could actually stop here! However, let’s do some enhancement
3. Display the Scoresheet
There’s a whole let we can do, but I’ll like to keep it simple for now. Later in the series, we would come back to this quiz.
So for now, let’s display a component that shows the final score and also give the user an option to replay.
The may topic is Conditional Rendering.
This is how it goes: we would have two divs in our template. The first div contains the quiz and conditionally renders if quizOver is false. The second div contains the scoresheet and renders if quizOver is false. The users score is displayed in the scoresheet. A “Retake Quiz” button is displayed as well.
The “Retake Quiz” button runs a function, retartQuiz(). The function simply resets the score, the index and the quizOver variable.
The complete html template is give below:
<!--This div renders if quizOver is false--> <div *ngIf="!quizOver"> <app-question [questionIndex]="currentIndex" (answers) ="receiveAnswers($event)" (totalQuestions)="getTotalQuestions($event)" > </app-question> <br> <button class="btn btn-outline-primary" (click)="goPrevious()">Previous</button> | <button class="btn btn-outline-success" (click)="goNext()">Next</button> </div> <!--This div renders if quizOver is true--> <div *ngIf="quizOver" class="border"> <h4>Quiz is Over!</h4> Your score is {{score}} / {{totalQuestions}} <br> <button (click)="restartQuiz()">Retake Quiz</button> </div>
The restartQuiz() function is given below.
restartQuiz() { this.quizOver = false; this.score = 0; this.currentIndex = 0; }
4. Force User to Select and Option
So far so good! But we are not done yet!. You’ll notice that the user can click Next even if though he has not selected an answer. Now we would disable the Next button if the user has not selected an option and enable it when he selects an option.
- a variable in child component, disable that is initially set to true (Question component).
- it emits true, in the onInit() method (Question component)
- when the user selects an option, this variable emits false (Questions component)
- this value is captured in the Quiz component, and used to set the variable, disabled(Quiz component)
- when the user clicks on Next, the variable disabled, is set to true(Quiz component)
I think it would have had less stress if we have used only one component. We’ll come back to this later in the series.
See complete app here in my GitHub repo. See how the logic hooks up. As I mentioned, later in the series, we would come back to this quiz to make it a bit standard.
Hi, The quiz folder is missing in the github. Could you please upload the latest code.
Thank you.
thanx a lot!!