New to Angular and need help rendering FormGroup in Angular Material table.
@Component({
selector: 'app-grid-view',
templateUrl: './grid-view.component.html',
styleUrls: ['./grid-view.component.scss']
})
export class GridViewComponent implements OnInit, AfterViewInit {
@Input() dataSource!: IndexDataSource;
@Input() sortField: string = 'id'
@Input() sortOrder: SortDirection = 'desc';
@Input() tableColumns: Array<IColumn> = [];
@Input() model = '';
// Handle pagination property
@ViewChild(MatPaginator, {static: false}) paginator!: MatPaginator;
// Handle sorting property
@ViewChild(MatSort, {static: false}) sort!: MatSort;
// Handle column that will be displayed
displayedColumns: Array<string> = [];
// For handling row search by each column
displayedColumnsSearch: Array<string> = [];
fieldsOfFormSearch: Array<any> = [];
// For filters, accommodate the filter inputs
filterValues: { [key: string]: string } = {};
filterString!: string;
// FormGroup to hold filter form controls
formGroup: FormGroup = new FormGroup({});
@Output() filterChange = new EventEmitter<{ [key: string]: string }>();
ngOnInit(): void {
// => Init rows based on param url
let paramMap = this.dataSource.activatedRoute.snapshot.queryParamMap;
this.dataSource.loadData(
Number(paramMap.get('page')) || 1,
Number(paramMap.get('per-page')) || 10,
paramMap.get('sort') || this.sortField,
paramMap.get('sort')?.startsWith("-") ? 'asc' : this.sortOrder,
paramMap.get('filter') || this.filterString
);
// => Column that will display in table
this.displayedColumns = this.tableColumns.map((column) => column.columnDef);
// => Form element that will be displayed in second row
this.fieldsOfFormSearch = this.tableColumns.map((column) => ({
status: column.isFilterable !== undefined,
formControl: new FormControl(),
urlSearch: this.model + `[${column.columnDef}]`,
}));
// => Create form controls for filter inputs and add them to the FormGroup
this.fieldsOfFormSearch
.filter((field) => field.status)
.forEach((field) => {
this.formGroup.addControl(field.urlSearch, field.formControl);
field.formControl.valueChanges
.pipe(debounceTime(300), distinctUntilChanged())
.subscribe((value: any) => {
this.filterValues[field.urlSearch] = value;
this.applyFilters();
});
});
// Column that will be display in table
this.displayedColumnsSearch = this.fieldsOfFormSearch.map((c) => c.urlSearch);
// Debug the form control
console.log(this.formGroup);
}
applyFilters() {
this.filterString = Object.keys(this.filterValues)
.map((key) => `${key}=${this.filterValues[key]}`)
.join('&');
this.dataSource.applyFilters(this.filterString);
this.filterChange.emit(this.filterValues);
}
}
The in `grid-view.component.html`
<!-- Actual Data -->
<ng-container *ngFor="let column of tableColumns;"
matColumnDef="{{column.columnDef}}">
<th mat-header-cell *matHeaderCellDef>{{column.header}}</th>
<td mat-cell *matCellDef="let element">{{column.cell(element)}}</td>
</ng-container>
<!-- Filter Data -->
<ng-container *ngFor="let field of fieldsOfFormSearch"
matColumnDef="{{field.urlSearch}}"
>
<th mat-header-cell *matHeaderCellDef>
<span *ngIf="!field.status; else displayField"></span>
<ng-template #displayField>
<!-- Filtering here-->
<mat-form-field appearance="fill">
<input
matInput
[formControl]="field.formControl"
(input)="applyFilters()"
>
</mat-form-field>
</ng-template>
</th>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matHeaderRowDef="displayedColumnsSearch"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>