2

I'm creating a quiz app and need to toggle between mat-checkbox or mat-radio-button, depending on whether the question has one or more answers. Question #1 is a single choice answer question and shows with mat-radio-button whereas Question #2 is a multiple answer question but is also displaying with mat-radio-button instead of mat-checkbox.

This is how my template looks like:

<form [formGroup]="formGroup">
    <ol *ngIf="multipleAnswer === false">
        // using mat-radio-buttons here 
    </ol>
    <ol *ngIf="multipleAnswer === true">
        // using mat-checkboxes here
    </ol>
</form>

and in my ts file the logic looks like:

multipleAnswer: boolean;

ngOnInit() {
  this.multipleAnswer = this.quizService.getQuestionType();
}

ngOnChanges(changes: SimpleChanges) {
  if (changes.question) {
    switch (this.question.type) {
      case 'SINGLE_CHOICE':
        this.formGroup = new FormGroup({
          answer: new FormControl([null, Validators.required])
        });
        break;
      case 'MULTIPLE_CHOICE':
        const multipleChoiceValidator = (control: AbstractControl) =>
          control.value.reduce(
            (valid: boolean, currentValue: boolean) => valid || currentValue
            , false
          ) ? null : {answers: 'At least one answer needs to be checked!'};
        this.formGroup = new FormGroup({
          answers: this.formBuilder.array(this.question.shuffledAnswers
              .map((answer: string) => this.formBuilder.control(false)),
            multipleChoiceValidator
          ),
        });
        break;
    }
  }
}

don't need shuffledAnswers, question type should be inferred from the assets/quiz.ts file (shouldn't need to hard code the question type), and answers should be numbers, not strings

in my QuizService:

getQuestionType(): boolean {
  return (this.correctAnswers && this.correctAnswers.length === 1);
}
5
  • I can't see your full code so i'll guess. Maybe the problem is you are checking multipleAnswer only once, inside ngOnInit. Did you try to check it in ngOnChanges? Commented May 1, 2020 at 20:53
  • yes I added it to ngOnChanges, but it doesn't seem to work. Commented May 2, 2020 at 15:39
  • I added the new ngOnChanges code shown above, but getting this error in the console: core.js:6237 ERROR NullInjectorError: R3InjectorError(QuizRoutingModule)[FormBuilder -> FormBuilder -> FormBuilder -> FormBuilder]: NullInjectorError: No provider for FormBuilder! Commented May 2, 2020 at 15:40
  • I can't say much from this sorry. Maybe if you can share the relevant parts as a stackblitz we can inspect that. Commented May 2, 2020 at 15:49
  • please see my stackblitz: stackblitz.com/edit/angular-9-quiz-app Commented May 2, 2020 at 16:50

1 Answer 1

1

There are several problems. First, calling multipleAnswer only inside ngOnInit sets this boolean variable only once at begining, it should be inside ngOnChanges.

But it's not the only issue here, the main problem is in your QuizService. Here you use this.quizService.getQuestionType(); method to set multipleAnswer true or false but inside your getQuestionType() method of QuizService you are checking this.correctAnswers if set and has element length of 1 but this.correctAnswers is always empty when you call it.

Another problem is in your ngOnChanges you have switch (this.question.type) here this.question seems to be undefined evertime.

Edit your code like below and check console outputs everytime a question appears.

Add a new method the get correctAnswers from a question.

getCorrectAnswers(question:QuizQuestion){
   return question.options.filter((item)=> item.correct);
}

And edit begining of ngOnChanges like below, i also added a console output so you can see the data from the new method above.

ngOnChanges(changes: SimpleChanges) {   
   if (changes.question && changes.question.currentValue !== changes.question.firstChange){
     this.currentQuestion = changes.question.currentValue;
     this.correctAnswers = this.getCorrectAnswers(this.currentQuestion);
     this.multipleAnswer = this.correctAnswers.length > 1 ? true : false;
     console.log('correct ans: ', this.correctAnswers);
     ...

I can't modify all of the code since you have your own logic behind your code, but i updated the answer so that variables related to this problem set correctly inside 'ngOnChanges`.

Sign up to request clarification or add additional context in comments.

9 Comments

Thanks for your help. I am still a little stuck. I've updated my stackblitz by adding this.multipleAnswer = this.correctAnswers.length > 1 ? true : false; to ngOnChanges (instead of using quizservice) and added the pushing of correctAnswers within the setSelected function. It seems like sometimes it works fine and sometimes it doesn't. The second question should use checkboxes (and should only select the first and second questions as correct answers).
Updated the answer and also forked your stackblitz and applied the solution. stackblitz.com/edit/angular-9-quiz-app-phgyaq
Thank you, but now I noticed that all the answers are now selecting as correct, and in the second question when answered correctly the score is not increasing.
Well, as i said in the answer,i can't modify all of the code since you have your own logic behind your code. But, you should adjust other parts of your code according to the changes we made, which is, when question changes you calculate everything inside ngOnChanges. For example you have setSelected method which is fired when radio button changed, there is still some calculation coming from quizService, check those if they are serving as intended.
Yea, I was able to fix the error easily, it was because the mat-radio-group and mat-checkbox-group were disabled. I could use some help with the mat-checkbox question (Question 2) doesn't seem to be incrementing when the correct answers are chosen.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.