J'essaie de construire une table modifiable en ligne en utilisant le dernier matériel + cdk pour angular.
Comment puis-je faire en sorte que mat-table utilise
[formGroupName]
afin que les champs de formulaire puissent être référencés par le chemin correct de leur formulaire?
C’est ce que j’ai eu jusqu’à présent: Exemple complet de StackBlitz
Modèle
<form [formGroup]="form">
<h1>Works</h1>
<div formArrayName="dates" *ngFor="let date of rows.controls; let i = index;">
<div [formGroupName]="i">
<input type="date" formControlName="from" placeholder="From date">
<input type="date" formControlName="to" placeholder="To date">
</div>
</div>
<h1>Wont work</h1>
<table mat-table [dataSource]="dataSource" formArrayName="dates">
<!-- Row definitions -->
<tr mat-header-row *matHeaderRowDef="displayColumns"></tr>
<tr mat-row *matRowDef="let row; let i = index; columns: displayColumns;" [formGroupName]="i"></tr>
<!-- Column definitions -->
<ng-container matColumnDef="from">
<th mat-header-cell *matHeaderCellDef> From </th>
<td mat-cell *matCellDef="let row">
<input type="date" formControlName="from" placeholder="From date">
</td>
</ng-container>
<ng-container matColumnDef="to">
<th mat-header-cell *matHeaderCellDef> To </th>
<td mat-cell *matCellDef="let row">
<input type="date" formControlName="to" placeholder="To date">
</td>
</ng-container>
</table>
<button type="button" (click)="addRow()">Add row</button>
</form>
Composant
export class AppComponent implements OnInit {
data: TableData[] = [ { from: new Date(), to: new Date() } ];
dataSource = new BehaviorSubject<AbstractControl[]>([]);
displayColumns = ['from', 'to'];
rows: FormArray = this.fb.array([]);
form: FormGroup = this.fb.group({ 'dates': this.rows });
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.data.forEach((d: TableData) => this.addRow(d, false));
this.updateView();
}
emptyTable() {
while (this.rows.length !== 0) {
this.rows.removeAt(0);
}
}
addRow(d?: TableData, noUpdate?: boolean) {
const row = this.fb.group({
'from' : [d && d.from ? d.from : null, []],
'to' : [d && d.to ? d.to : null, []]
});
this.rows.Push(row);
if (!noUpdate) { this.updateView(); }
}
updateView() {
this.dataSource.next(this.rows.controls);
}
}
Cela ne fonctionnera pas. Rendements de la console
Erreur ERREUR: Impossible de trouver le contrôle avec le chemin: 'dates -> de'
Il semble que le [formGroupName]="i"
n'ait aucun effet, car le chemin devrait être dates -> 0 -> from
lors de l'utilisation d'un formArray.
Ma solution actuelle: Pour ce problème, j'ai contourné la recherche de chemin interne (formControlName="from"
) et utilisé directement le contrôle de formulaire: [formControl]="row.get('from')"
, mais je voudrais savoir comment je peux Je ne peux pas) utiliser la méthode préférée de la forme réactive.
Tous les conseils sont les bienvenus. Je vous remercie.
Puisque je pense que c'est un bug, j'ai enregistré un problème avec le dépôt angular/material2 github.
Je voudrais utiliser l'index que nous pouvons obtenir dans matCellDef
contraignant:
*matCellDef="let row; let index = index" [formGroupName]="index"
voici l exemple de code
En HTML:
<form [formGroup]="tableForm">
<mat-table formArrayName="users" [dataSource]="dataSource">
<ng-container cdkColumnDef="position">
<mat-header-cell *cdkHeaderCellDef> No. </mat-header-cell>
<mat-cell *cdkCellDef="let row let rowIndex = index" [formGroupName]="rowIndex">
<input type="text" size="2" formControlName="position"> </mat-cell>
</ng-container>
<ng-container cdkColumnDef="name">
<mat-header-cell *cdkHeaderCellDef> Name </mat-header-cell>
<mat-cell *cdkCellDef="let row let rowIndex = index" [formGroupName]="rowIndex">
<input type="text" size="7" formControlName="name">
</mat-cell>
</ng-container>
<ng-container cdkColumnDef="weight">
<mat-header-cell *cdkHeaderCellDef> Weight </mat-header-cell>
<mat-cell *cdkCellDef="let row let rowIndex = index" [formGroupName]="rowIndex">
<input type="text" size="3" formControlName="weight">
</mat-cell>
</ng-container>
<ng-container cdkColumnDef="symbol">
<mat-header-cell *cdkHeaderCellDef> Symbol </mat-header-cell>
<mat-cell *cdkCellDef="let row let rowIndex = index" [formGroupName]="rowIndex">
<input type="text" size="2" formControlName="symbol">
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *cdkHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *cdkRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
Code du contrôleur:
displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
dataSource ;
tableForm: FormGroup;
constructor(private formBuilder: FormBuilder){
this.dataSource = [
{position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
{position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
{position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'},
{position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N'},
{position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O'},
{position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F'},
{position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne'},
];
}
ngOnInit(){
this.tableForm= this.formBuilder.group({
users: this.formBuilder.array([])
})
this.setUsersForm();
this.tableForm.get('users').valueChanges.subscribe(users => {console.log('users', users)});
}
private setUsersForm(){
const userCtrl = this.tableForm.get('users') as FormArray;
this.dataSource.forEach((user)=>{
userCtrl.Push(this.setUsersFormArray(user))
})
};
private setUsersFormArray(user){
return this.formBuilder.group({
position:[user.position],
name:[user.name],
weight:[user.weight],
symbol:[user.symbol]
});
}