Search code examples
angulartypescriptangular-materialangular-forms

Angular table with multiple header column input filter


I have an Angular table with three columns. In the table header, all these three columns have three input fields.

Three inputs: Stock Number, Case, Availability.

User can search with Single Input(Stock Number OR Case OR Availability), two inputs(AND condition of any 2 inputs) or all three inputs(AND of all 3 inputs).

I have written code for 3 inputs scenario with AND operator. How to change this logic to all input usecases?

I am looking for a solution, where if the user enters three inputs {stockNumber: 'XYZ5000', caseNum: '1991', availability: 'AVAILABLE'}. It has to be compared with stockDetailsList(in stock response object) and collect the filtered result in another stock object(Just print filtered stock bject in console.log).

AppComponent file:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { MatTableDataSource } from '@angular/material/table';

const stock:any[] = [
  {
  stockId: 'XYZ5000', stockDetailsList: [
    {stockNumber: 'XYZ5000', caseNum: '1991', availability: 'AVAILABLE'},
    {stockNumber: 'XYZ5000', caseNum: '2001', availability: 'AVAILABLE'},
    {stockNumber: 'XYZ5000', caseNum: '2023', availability: 'AVAILABLE'},
    {stockNumber: 'XYZ5000', caseNum: '2000', availability: 'NOTAVAILABLE'},
    {stockNumber: 'XYZ5000', caseNum: '1997', availability: 'AVAILABLE'},
    {stockNumber: 'XYZ5000', caseNum: '2015', availability: 'AVAILABLE'}
    ],
  },
  {
  stockId: 'XYZ1000', stockDetailsList: [{stockNumber: 'XYZ1000', caseNum: '2015', availability: 'AVAILABLE'}
    ],
  },
  {
  stockId: 'XYZ4000, NEW.', stockDetailsList: [{stockNumber: 'XYZ4000', caseNum: '2012', availability: 'AVAILABLE'}
    ],
  }
];

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  title = 'MultiInputFilters';
  stockForm!: FormGroup;
  pageList:any[] = [];
  public displayedColumns: string[] = ['stockId', 'caseNum', 'availability'];
  public dataSource = new MatTableDataSource<any>([]);
  
  constructor() {
    this.stockForm = new FormGroup({
      stockNumber: new FormControl(),
      caseNum: new FormControl(),
      availability: new FormControl(),
    });
  }

  
  ngOnInit(): void {
    const objectArray: any[] = [];
    this.generateTableRows(stock, objectArray);
    this.dataSource = new MatTableDataSource(objectArray);
  }
  
  public generateTableRows(stock: any[], objectArray: any[]): void {
    stock.forEach(s => {
      objectArray.push({ stockId: s.stockId });
      if (s.stockDetailsList?.length) {
        s.stockDetailsList.forEach((x: any) => objectArray.push({
          stockNumber: x.stockNumber,
          caseNum: x.caseNum,
          availability: x.availability,
        }))
      }
    });
    console.log('generateTableRows objectArray: '+ objectArray);
  }


  applyFilter() {
    this.pageList = [];
    const objectArray: any[] = [];
    const { stockNumber, caseNum , availability } = this.stockForm.value;
    this.pageList = stock.filter(s => {
      s.stockDetailsList.filter((x: any) => {

        if (((stockNumber && stockNumber.includes(x.stockNumber))) && (caseNum && caseNum.includes(x.caseNum)) && (availability && availability.includes(x.availability))) {
          objectArray.push({ stockId: s.stockId });
          objectArray.push({
            stockNumber: x.stockNumber,
            caseNum: x.caseNum,
            availability: x.availability,
          })
        }

      });
    });
    console.log("applyFilter objectArray: "+ objectArray);
    this.dataSource = new MatTableDataSource(objectArray);
    //this.dataSource.filter = JSON.stringify(objectArray); => this.dataSource.filter is preferable than MatTableDataSource
  }

}

Stackblitz of complete project: https://stackblitz.com/edit/angular-ivy-38zpmg?file=src%2Fapp%2Fapp.component.ts, https://angular-ivy-38zpmg.stackblitz.io

Technologies used:

  • Angular
  • TypeScript
  • Angular Forms
  • Angular Material

enter image description here


Solution

  • customFilter = (data: PeriodicElement, filter: string) => {
        const filterData = JSON.parse(filter);
        //filterData will be like: {stockNumber:..,caseNum:..,availability:...,name:...}
    
        bool find=!filterData.stockNumber || filterData.stockNumber.includes(data.stockNumber);
        find=find && (!filterData.caseNum || filterData.caseNum.includes(data.caseNum)
        find=find && (!filterData.availability|| filterData.availability.includes(data.availability)
        find=find && (!filterData.name|| data.name.indexOf(filterData.name)>=0)
        return find
      };