1

In Angular, I use a Material table with expanded rows and I want to filter it with the RequestId

table-tree.html

<div class="filter">
<span>
  <h5 class="requestid">Request ID</h5>
  <input type="text" [(ngModel)]="requestFilter" />
</span>
</div>

<table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8">
  <ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
    <th mat-header-cell *matHeaderCellDef>{{columnNames[column]}}</th>
    <td mat-cell *matCellDef="let element">
      {{element[column]}}
    </td>
  </ng-container>

  <ng-container matColumnDef="expandedDetail">
    <td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
      <div class="example-element-detail" [@detailExpand]="element == expandedInfo ? 'expanded' : 'collapsed'">
        <div class="example-element-position">{{element.creationDate}}</div>
        <div class="example-element-description">
          {{element.serialNumberProductRefToSupply}}
        </div>
        <div class="example-element-description">
          {{element.serialNumberOriginSupplyToDestination}}
        </div>
      </div>
    </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
  <tr mat-row *matRowDef="let element; columns: columnsToDisplay;" class="example-element-row"
    [class.example-expanded-row]="expandedInfo === element" (click)="expandedInfo = element"></tr>
  <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
</table>

table-tree.ts

import { Component } from '@angular/core';
import {
  animate,
  state,
  style,
  transition,
  trigger
} from '@angular/animations';

@Component({
  selector: 'table-tree',
  styleUrls: ['table-tree.css'],
  templateUrl: 'table-tree.html',
  animations: [
    trigger('detailExpand', [
      state(
        'collapsed',
        style({ height: '0px', minHeight: '0', display: 'none' })
      ),
      state('expanded', style({ height: '*' })),
      transition(
        'expanded <=> collapsed',
        animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')
      )
    ])
  ]
})

export class TableTree {
  dataSource = MoveOrderData;
  expandedInfo: MoveOrderAuthorizations;
  requestFiltered = '';

  get requestFilter(): string {
    return this.requestFiltered;
  }
  set requestFilter(value: string) {
    console.log(value);
    this.requestFiltered = value;
    this.filteredRequests = this.performFilter(value);
  }
  filteredRequests: MoveOrderAuthorizations[] = [];

  performFilter(filterBy: string): MoveOrderAuthorizations[] {
    filterBy = filterBy.toLocaleLowerCase();
    return this.dataSource.filter((request: MoveOrderAuthorizations) =>
      request.requestId.includes(filterBy));
  }

  columnsToDisplay = [
    'creationDate',
    'requestId',
    'issue',
    'requestType',
    'managedBy',
    'serialNumberProductRefToSupply',
    'serialNumberOriginSupplyToDestination'
  ];

  columnNames = {
    creationDate: 'Creation Date',
    requestId: 'Request ID',
    issue: 'Issue',
    requestType: 'Request Type',
    managedBy: 'Managed by',
    serialNumberProductRefToSupply: 'Product ref to supply',
    serialNumberOriginSupplyToDestination: 'Origin supply to Destination'
  };

  responseColumnsToDisplay = ['moveorderId', 'originDestination', 'status'];
  subColumnNames = {
    moveorderId: 'Move Order ID',
    originDestination: 'Origin Destination',
    status: 'Status'
  };

}

export interface MoveOrderAuthorizations {
  creationDate: string;
  requestId: string;
  issue: string;
  requestType: string;
  managedBy: string;
  serialNumberProductRefToSupply: string;
  serialNumberOriginSupplyToDestination: string;
}

const MoveOrderData: MoveOrderAuthorizations[] = [
  {
    creationDate: `01/01/2021`,
    requestId: '139322',
    issue: ``,
    requestType: `Evacuation`,
    managedBy: `AGV`,
    serialNumberProductRefToSupply: `ML132345XO1211321AND11432001`,
    serialNumberOriginSupplyToDestination: `SA-11EOL-LN001`
  },
  {
    creationDate: `01/01/2021`,
    requestId: '254982',
    issue: `Destination not found`,
    requestType: `Supply`,
    managedBy: `AGV`,
    serialNumberProductRefToSupply: `ML132345XO1211321AND11432002`,
    serialNumberOriginSupplyToDestination: `RE-11WIP-11E03`
  }
];

I wrote a method with getter and setter to filter the data which are displayed but something miss and it doesn't work.

  performFilter(filterBy: string): MoveOrderAuthorizations[] {
    filterBy = filterBy.toLocaleLowerCase();
    return this.dataSource.filter((request: MoveOrderAuthorizations) =>
      request.requestId.includes(filterBy));
  }
  requestFiltered = '';

  get requestFilter(): string {
    return this.requestFiltered;
  }
  set requestFilter(value: string) {
    console.log(value);
    this.requestFiltered = value;
    this.filteredRequests = this.performFilter(value);
  }
  filteredRequests: MoveOrderAuthorizations[] = [];

You can go and see the table on Stackblitz > [https://stackblitz.com/edit/tab-tree-filter?file=app/table-tree.ts][1]

Thanks :)

bengabo
  • 53
  • 1
  • 8

1 Answers1

1

The issues here is you are using datasource variable for mat-table. However, when you are filtering the items, then you are storing them in another array named requestsFiltered and not updating datasource. Hence the table is not getting updated even when the items are filtered.

Please check the updated code.

Changes done (according to stackblitz code):

HTML(made the datasource to be requestFiltered):

<table mat-table [dataSource]="filteredRequests" multiTemplateDataRows class="mat-elevation-z8">

TS:

  1. Initialized the requestsFiltered to that of original unfiltered datasource
  ngOnInit() {
    this.filteredRequests = this.dataSource;
  }
  1. Changed the performFilter function
performFilter(filterBy: string): MoveOrderAuthorizations[] {
    filterBy = filterBy.toLocaleLowerCase();
    this.filteredRequests = this.dataSource.filter(
      (request: MoveOrderAuthorizations) => request.requestId.includes(filterBy)
    );
    return !!filterBy && this.filteredRequests.length > 0
      ? this.filteredRequests
      : this.dataSource;
}
Drashti Dobariya
  • 2,455
  • 2
  • 10
  • 23
  • Thank you, Drashti Dobariya. It's very clear now. I have a question about the performFilter function. Can you tell me what "!!" is for ? – bengabo Jul 09 '21 at 09:35
  • Double negation is used for consise case to boolean. You can find detailed explanation [here](https://stackoverflow.com/questions/10467475/double-negation-in-javascript-what-is-the-purpose) – Drashti Dobariya Jul 09 '21 at 09:50