angular mat-checkbox dynamically with ngModel

Viewed 68413

I have a class Offer which have one property "units" as array of objects.

export class Offer {
   public propertyA: string;
   public propertyB: string;
   public units: Unit[];
}

export class Unit {    
    public code: string,
    public name: string,
    public checked: boolean
}

I am using Angular2, these units must be checkboxes the user can select. Also I am using angular material.

The html code looks like:

<div *ngFor="let unit of model.units; let i=index">
  <mat-checkbox [(ngModel)]="model.units[i].checked"
    id="units[{{i}}]" name="units[{{i}}]">
       {{ unit.name }}
  </mat-checkbox>                        
</div>    

The units property is loaded using:

this.model.units.push(new Unit("code1","name1", false));
this.model.units.push(new Unit("code2","name2", false));
this.model.units.push(new Unit("code3","name3", false));

When I send the form the checked property does not contains the checked value.

What am I doing wrong??

5 Answers

This work for me tested in Angular 7.

Just to make sure that name is unique for each checkbox

<mat-grid-list cols="4" rowHeight="100px">
                    <mat-grid-tile *ngFor="let item of aspNetRolesClaims" [colspan]="1" [rowspan]="1">
                        <span>{{item.claimValue}}</span>
                        <mat-checkbox [(ngModel)]="item.claimValue" name="{{item.claimType}}">{{item.claimType}}</mat-checkbox>
                    </mat-grid-tile>
                </mat-grid-list>

I tested in Angular 7 and I couldn't find any error given your question and you can see a working demo in this StackBlitz example, but here goes my answer.

In order to work you gotta give an unique name to your ngModel binded input.

Example taking your code:

<div *ngFor="let unit of model.units; let i=index">
  <mat-checkbox 
    [(ngModel)]="model.units[i].checked"
    id="units-{{i}}" 
    name="units-{{i}}" // using plain slug-case instead of array notation
  >
      {{ unit.name }}
  </mat-checkbox>                        
</div> 

I prefer not to use the array notation in these cases (units[{{i}}]), because it means that all fields are joined in the same thing, but as your code seems to work this is just a preference and not the cause of the error.

If you cannot use [(ngModel)] like when you are using a FormGroup, you can do the following. The code assumes that obj is the custom object and has a IsSeleted property.

<mat-checkbox [checked]="obj.IsSelected"                                      
 (change)="onSelectionChanged($event, obj)">{{obj.Name}}
</mat-checkbox>

And inside onSelectionChanged, update the obj.IsSelected manually

public onSelectionChanged(arg: MatCheckboxChange, obj:any) {
 obj.IsSelected = arg.checked;
}

One more possible way that might be simpler. This approach is working fine within a form group

<form [formGroup]='formGroup'>
    <mat-checkbox [(ngModel)]="obj.IsSelected" [ngModelOptions]="{standalone:> true}">
        {{obj.Name}}
    </mat-checkbox>
</form>
Related