based on my html below , as you can see I have a table and then looped through mat cell using *matCellDef="let model"
, inside the cell there are input fields which are reactive forms (it has mat error checking ,formcontrolname etc).
Each cell or row should have its own reactive form since each row has its own mat form fields input fields and validations.
How do we address this in angular?. I have provided some code snippets below that might help. highly appreciated. Thanks.
#html code
<mat-table [dataSource]="table.dataSource" [@animateStagger]="{value:'50'}" matMultiSort (matSortChange)="table.onSortEvent()"> <ng-container matColumnDef="id"> <mat-header-cell *matHeaderCellDef mat-multi-sort-header="id"> <span class="text-left">COLUMN 1</span> </mat-header-cell> <mat-cell *matCellDef="let model" class="p-2"> <form [formGroup]="modelForm"> <div fxLayout="row" class="inspection-schedule-property-border-bottom" style="width: 99%;"> <div fxFlex="40" class="inspection-schedule-property-header-sub-label"> <mat-form-field appearance="fill" style="padding-right: 8px;" fxFlex="40"> <mat-label> enter date </mat-label> <mat-date-range-input> <input matStartDate placeholder="start date" required formControlName="start"> <input matEndDate placeholder="end date" required formControlName="end"> </mat-date-range-input> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-date-range-picker #picker></mat-date-range-picker> <mat-error *ngIf="modelForm.controls.start.hasError('required')">Start date is required</mat-error> <mat-error *ngIf="modelForm.controls.end.hasError('required')">End date is required</mat-error> </mat-form-field> </form> </mat-cell> </ng-container> </mat-table>
#ts code
modelForm: FormGroup;
this.modelForm = this._createModelForm(); private createModelForm(): FormGroup { return this.formBuilder.group({ start: new FormControl(Validators.required), end: new FormControl(Validators.required), }); }
#code that pulls data from api to be populated on table
ngOnInit(): void { this.table.dataSource = new MatMultiSortTableDataSource(this.sort, this.CLIENT_SIDE); this.table.nextObservable.subscribe(() => { this.getDetails();}); this.table.sortObservable.subscribe(() => { this.getDetails();}); this.table.previousObservable.subscribe(() => {this.getDetails();}); this.table.sizeObservable.subscribe(() => {this.getDetails();}); } private getDetails() { this.isLoading = true; this.service .getDetails(this.filterModel) .pipe(finalize(() => (this.isLoading = false))) .subscribe({ next: (res) => { this.table.data = res.items as Array<any>; this.table.totalElements = res.totalItemCount; }, error: (err) => { }, complete: noop, }); }
Advertisement
Answer
We have a ngx-multi-sort-table. The tecnica is similar
If we see in github the source
We see that we can override the function “_sortData” that belong to the class “MatMultiSortTableDataSource”, so we can do some like this in initData
initData() { this.table.dataSource = new MatMultiSortTableDataSource(this.sort, this.CLIENT_SIDE); this.table.dataSource._sortData=(d1: AbstractControl, d2: AbstractControl, params: string[], dirs: string[]): number =>{ if (d1.value[params[0]] > d2.value[params[0]]) { return dirs[0] === 'asc' ? 1 : -1; } else if (d1.value[params[0]] < d2.value[params[0]]) { return dirs[0] === 'asc' ? -1 : 1; } else { if (params.length > 1) { params = params.slice(1, params.length); dirs = dirs.slice(1, dirs.length); return this.table.dataSource._sortData(d1, d2, params, dirs); } else { return 0; } } } .... }
And when create the data we use some like
this.table.data = res.users.map(x=>this.createGroup(x));
Another option is create a class that extends from “MatMultiSortTableDataSource”
export class MatMultiSortTableDataSourceControls<T> extends MatMultiSortTableDataSource<T> { constructor(sort: MatMultiSort, clientSideSorting = false) { super(sort,clientSideSorting); } _sortData=(dd1: T, dd2: T, params: string[], dirs: string[]): number =>{ const d1=dd1 as any const d2=dd2 as any if (d1.value[params[0]] > d2.value[params[0]]) { return dirs[0] === 'asc' ? 1 : -1; } else if (d1.value[params[0]] < d2.value[params[0]]) { return dirs[0] === 'asc' ? -1 : 1; } else { if (params.length > 1) { params = params.slice(1, params.length); dirs = dirs.slice(1, dirs.length); return this._sortData(d1, d2, params, dirs); } else { return 0; } } } }
And use
this.table.dataSource=new MatMultiSortTableDataSourceControls(this.sort,this.CLIENT_SIDE)
See a stackblitz