Reputation: 865
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??
Upvotes: 25
Views: 88066
Reputation: 831
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>
Upvotes: 0
Reputation: 519
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;
}
Upvotes: 1
Reputation: 10324
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.
Upvotes: 5
Reputation: 17078
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>
Upvotes: 11
Reputation: 6701
Add [checked]="unit.checked"
and remove ngModel
, id
and name
from your mat-checkbox
. This does one way binding when you load the page but to make the two way binding work you need to do something similar like this which i have done in my project:
Pass the $event
on change and set the value in the component file manually:
Change your HTML to:
<div *ngFor="let unit of model.units">
<mat-checkbox [checked]="unit.checked"
(change)="valueChange(model.units,unit,$event)">
{{ unit.name }}
</mat-checkbox>
</div>
Add this to Component file:
valueChange(model.units, unit, $event) {
//set the two-way binding here for the specific unit with the event
model.units[unit].checked = $event.checked;
}
EDIT/UPDATE: Found a solution recently for two way binding without handling it explicitly
Make sure model.units
have a property for checked
. This is the easiest way to add it:
component.ts:
this.model.units.forEach(item => {
item.checked = false; //change as per your requirement
});
html:
<div *ngFor="let unit of model.units;let i=index">
<mat-checkbox [(ngModel)]="unit.checked" [checked]="unit.checked"
name="{{i}}-name"> //make sure name is unique for every item
</mat-checkbox>
</div>
If you want to control the enable/disable options as well try adding this:
component.ts:
this.model.units.forEach(item => {
item.checked = false;//change as per your requirement
item.disabled = true;//change as per your requirement
});
html:
<div *ngFor="let unit of model.units;leti=index">
<mat-checkbox [(ngModel)]="unit.checked" [checked]="unit.checked"
[disabled]="unit.disabled"
name="{{i}}-name">//make sure name is unique for every item
</mat-checkbox>
</div>
Upvotes: 45