5
votes

I'm implementing a language switch component which display checkboxes, one for each language of the app (translations with @ngx-translate).

When clicking one of the checkbox, app language is correctly switched but the clicked mat-checkbox is still unchecked.

Template :

<mat-checkbox [checked]="selectedLanguage == 'en'" (click)="switchLanguage('en')">English</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage == 'fr'" (click)="switchLanguage('fr')">French</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage == 'de'" (click)="switchLanguage('de')">German</mat-checkbox>

Component :

export class CheckboxOverviewExample {
  public selectedLanguage: string;

  constructor(){
    this.selectedLanguage = 'fr';
  }

  public switchLanguage(lang: string) {
    this.selectedLanguage = lang;
    // this.translateService.use(lang); // changing ngx-translate language
    console.log('Switched to ' + lang);
  }
}

The [checked] binding is working when you route to the component. The mat-checkbox for french is indeed checked when landing to the component (default value). Now when I click on german or english, the language does switch, the french checkbox does correctly uncheck, however the clicked checkbox does not check.

I'm missing something, might be a small detail, but I do not understand why the german / english does not check while the french does correctly uncheck.

Have a look at this simple stackblitz code to reproduce my case.

4
Why don't you use ngModel instead of checked? - Igor Dimchevski
ngModel should map to a boolean value I do not have. I have a language field which can take several string values. Moreover, the number of languages can increase due to app parameters (in my real code, checkboxes are rendered with a *ngFor directive). - Wis
Use radio button, that will allow you to bind language property as ngModel. - Igor Dimchevski

4 Answers

7
votes

so I have an answer for you. don't need to use a radio button as your designer hate it just use

<mat-checkbox [checked]="selectedLanguage === 'en'" (change)="switchLanguage('en')">English</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage === 'fr'" (change)="switchLanguage('fr')">French</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage ==='de'" (change)="switchLanguage('de')">German</mat-checkbox>

check for type and value too using selectedLanguage === 'en'

also, use (change)="switchLanguage('de') instead of click

working here or check this

6
votes

You should use (change) instead of (click). Your template should be changed to this:

<mat-checkbox [checked]="selectedLanguage === 'en'" (change)="switchLanguage($event, 'en')">English</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage === 'fr'" (change)="switchLanguage($event, 'fr')">French</mat-checkbox>
<mat-checkbox [checked]="selectedLanguage === 'de'" (change)="switchLanguage($event, 'de')">German</mat-checkbox>

... and your function will look like this:

public switchLanguage(event: MatCheckboxChange, lang: string) {
    if(event.checked && this.selectedLanguage!== lang){
        this.selectedLanguage = lang;
        // this.translateService.use(lang); // changing ngx-translate language
        console.log('Switched to ' + lang);
    }
}

Remember to import MatCheckboxChange

import { MatCheckboxChange} from '@angular/material';`

Link to Demo.


You should use radio buttons for this behavior. Checkbox is not the correct way to go when you only have to allow a single option selection.

<mat-radio-group [value]="selectedLanguage">
  <mat-radio-button value="en" (click)="switchLanguage('en')">English</mat-radio-button>
  <mat-radio-button value="fr" (click)="switchLanguage('fr')">French</mat-radio-button>
  <mat-radio-button value="de" (click)="switchLanguage('de')">German</mat-radio-button>
</mat-radio-group>

Here is a StackBlitz Demo.

2
votes

Alternatively to other answers you can choose not to use a separate function to handle the change event, but instead assign a value like this: (change)="myBooleanVar = $event.source.checked" This example does not work in OP's case, but might be useful to other people who use checkboxes to assign yes/no values.

0
votes

(click) is a DOM event, whereas (change) is generated from the Angular framework.

Click will have a generic DOM event object, and Change the MatCheckboxChange object.

Click fires first.