Utilizing Angular's form group for effective row filtering in Angular Material Table

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>

Answer №1

When working with "field.formControl" as strings, you have the option to enclose the table in a

<form [formGroup]="formGroup">
and use
[formControlName]="field.formControl"
rather than using "[formControl]".

Alternatively, you can create the formGroup beforehand and then map it like this:

this.fieldsOfFormSearch = this.tableColumns.map((column) => ({
      status: column.isFilterable !== undefined,
      // Make sure to assign the formControl property to a FormControl object
      formControl: this.formGroup.get(column.columnDef + 'Search') as FormControl,
      urlSearch: this.model + `[${column.columnDef}]`,
    }));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

`Incorporate concurrent network requests in React for improved performance`

I am looking to fetch time-series data from a rest service, and currently my implementation looks like this async function getTimeSeriesQuery(i) { // Demonstrating the usage of gql appollo.query(getChunkQueryOptions(i)) } var promises = [] for(var i ...

Issue with Framer-motion animation not triggering on exit

Here is a link to the code sandbox In this gif demonstration, it's evident that the notifications are not triggering the exit animation when removed from the DOM (usually after 6 seconds). Why is this happening? I've followed all the suggestion ...

Utilizing winston to generate multiple log files with set maximum sizes and daily rotation

Currently, I am utilizing winston for logging with a maximum size and daily rotation. I am interested in having this functionality with one file per API endpoint to define multiple log files. Is there a way to achieve this? Displayed below is my winston ...

Definition of a class in Typescript when used as a property of an object

Currently working on a brief .d.ts for this library, but encountered an issue with the following: class Issuer { constructor(metadata) { // ... const self = this; Object.defineProperty(this, 'Client', { va ...

Developing with Ionic 2 allows you to efficiently run a background service using Cordova

I am currently using Ionic 2 and I have a requirement for my app to perform certain tasks even when it is closed, similar to how Gmail continues to provide notifications all the time. After some research, I came across this documentation: https://ionicfr ...

What is the process of converting a union type into a union of arrays in TypeScript?

I have a Foo type that consists of multiple types For example: type Foo = string | number I need to receive this type and convert it into an array of the individual types within the union type TransformedFoo = ToUnionOfArray<Foo> // => string[] ...

How should the ternary operator be properly utilized in React and Typescript?

Currently, I have the following code snippet in use: render: props.columnLinks[key] ? ((text): ReactElement => <a href={props.columnLinks[key]}>{text}</a>) : undefined, However, I am looking to simplify this statement ...

Once the Angular project has been initialized, the Button disable attribute cannot be modified

In my Ionic-Angular project, I am creating registration pages where users input their information in multiple steps. For each step, there is a button that remains disabled until the correct information is entered. An issue arises when transitioning to the ...

WebStorm provides alerts for objects, types, and directives within Angular, yet they function properly

Why is WebStorm displaying warnings for objects, types, and directives in Angular Template HTML even though they are functioning correctly? Despite the fact that all types and Angular directives in the HTML structure are working fine within Angular on Web ...

Encountering a "Multiple registrations of the method 'get' on the path '../api/' error" with Swagger

I am utilizing OpenAPI / Swagger in an Angular application built on .NET Core, and I am facing the error "The method 'get' on path '../api/' is registered multiple times" while generating frontend TypeScript code using NSwag Studio. Fro ...

Encountered an issue while trying to install ngrx store with Angular 13 - unable to resolve the dependency

Encountering an error with the following command: ng add @ngrx/store@latest The error message reads as follows: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: <a href="/cdn-cgi/l/email-prot ...

Angular 8 Refresh Token Implementation

I am currently working on an Angular 8 app that is integrated with .NET Core. My goal is to find a way to refresh a JWT token within the application. Within the integration, users are able to validate and receive a token which expires after 30 minutes. T ...

Binding textarea data in Angular is a powerful feature that allows

I am looking to display the content from a textarea on the page in real time, but I am struggling to get the line breaks to show up. Here is my current code snippet: app.component.html <div class="ui center aligned grid">{{Form.value.address}}< ...

How can I properly prevent the use of a nested observable subscription within a loop?

Utilizing Angular2 along with Firebase through Angularfire2 to retrieve data from a Firebase Realtime Database, which essentially consists of a large JSON object. The current setup involves a polling system where polls are stored in a 'Polls' no ...

"NgFor can only bind to Array objects - troubleshoot and resolve this error

Recently, I've encountered a perplexing error that has left me stumped. Can anyone offer guidance on how to resolve this issue? ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supp ...

Error encountered in Angular: FormBuilder provider not found

I am currently utilizing Angular 9. An error that I am encountering is as follows: No provider for FormBuilder This issue has been documented in numerous instances, with the common solution being to include the FormsModule in the app.module.ts file. F ...

Tips for instantiating a class with another class as a variable?

When using typescript, I am passing an entire class as a reference MyClass to a function. How can I create a new instance of that class within the function? export class MyClass { } createClass(MyClass); function createClass(classReference) { const c ...

Angular2 boasting its recursive dynamic template compilation

My work is inspired by a similar issue discussed here: creating and compiling dynamic Components with Angular 2.0 How can I use/create dynamic template to compile dynamic Component with Angular 2.0? The functional plunker mentioned in the question above ...

The Ultimate Guide to Resolving Angular TrustedHTML Assignment Issues

(I seem to be facing an issue related to encountering the error message `This document requires 'TrustedHTML' assignment` in Chrome, despite using Angular v10) Context: Whenever I apply the [innerHTML]="myVar" directive on an Angular ...

Troubleshooting display glitches on Bootstrap modals in Internet Explorer 11 and Microsoft Edge

I have been encountering rendering artifacts consistently across various versions of IE11 and Edge, on different devices with varying graphics cards and drivers, as well as different update statuses of Windows 10. The screenshots indicate some of these ar ...