integral100x
integral100x

Reputation: 342

How can I toggle between mat-checkbox or mat-radio-button in Angular reactive form?

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);
}

Upvotes: 2

Views: 1266

Answers (1)

CeritT
CeritT

Reputation: 532

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`.

Upvotes: 1

Related Questions