How to show a empty message in dynamic data table angular

13,869

Solution 1

You can't reach what you want using *ngIf="dataSource.length === 0" condition simply because the data source doesn't change at all when you do filtering. what you have to do is watch out for the filtered data length. you can use something like following: *ngIf="dataSource.filteredData.length > 0" as the condition. the length of datasource.filteredData changes based on the filtered results. this condition can hide your table. you can put this in your table tag like: <table mat-table [dataSource]="dataSource" *ngIf="dataSource.filteredData.length > 0">

Solution 2

One caveat to using ngIf. If you're using matSort and you nest the table inside a block using *ngIf, then the sorting will not work because the ngIf sets the viewChild to undefined. Reference

Use [ngClass] to get around this

<div [ngClass]="dataSource.filteredData.length > 0 ? 'visible': 'hidden'">
  <mat-table #table [dataSource]="dataSource" matSort>
    <ng-container matColumnDef="name">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Name </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
    </ng-container>
    <ng-container matColumnDef="age">
      <mat-header-cell *matHeaderCellDef mat-sort-header>Age </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.age}} </mat-cell>
    </ng-container>
    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="row.toggle(row)">
    </mat-row>
  </mat-table>
</div>
<div [ngClass]="dataSource.filteredData.length > 0 ? 'hidden': 'visible'">
  <tr>No results found.</tr>
</div>

Here is the CSS for the classes

.hidden {
  visibility: hidden;
}

.visible {
  visibility: visible;
}

Solution 3

For a mat-table, prior to v10, you could give the table a row of data when your dataSource is empty by doing this: [dataSource]="dataSource.data.length > 0 && dataSource.data.filteredData > 0 ? dataSource : emptyDataSource" Then create a column def for your cell to display the empty data message: <ng-container vdlColumnDef="empty-row"> <td *matCellDef="let row" mat-cell [colSpan]="displayedColumns.length">No Data</td> </ng-container> Then change your row def to show the empty row column def when dataSource is empty: <tr mat-row *matRowDef="let row; columns: dataSource.data.length > 0 && dataSource.data.filteredData > 0 ? displayedColumns : ['empty-row'];">

https://stackblitz.com/edit/angular-mat-table-no-data?file=src%2Fapp%2Ftable-basic-flex-example.html

After Angular Material 10, they've added a directive for when there is no data in the table: 'If you want to show a message when not data matches the filter, you can use the *matNoDataRow directive.' https://v10.material.angular.io/components/table/overview#filtering

Share:
13,869

Related videos on Youtube

TinyRex
Author by

TinyRex

Updated on June 04, 2022

Comments

  • TinyRex
    TinyRex almost 2 years

    I try to show an empty message error when the filter doesn't have matches with:

    <div *ngIf="dataSource.length === 0">No data</div>
    

    but it doesn't work because I build a dynamic table with MatTableDataSource.

    For a better understanding, I changed my dynamic table for an array predefined.

    const ELEMENT_DATA: MembersElement[] = [
    { name: 'Jenny', age: 17 },
    { name: 'Daniel', age: 18 }
    ];
    

    However, is necessary using MatTableDataSource to a dynamic building of the users' table

    This is all my ts code.

        import { Component, OnInit } from '@angular/core';
    import {MatTableDataSource} from '@angular/material';
    
    export interface SociosElement {
      nombre: string;
      edad: number;
    }
    
    const ELEMENT_DATA: MembersElement[] = [
      { name: 'Jenny', age: 17 },
      { name: 'Daniel', age: 18 }
    ];
    
    @Component({
      selector: 'app-pruebas',
      templateUrl: './tableMembers.component.html',
      styleUrls: ['./tableMembes.component.css']
    })
    export class PruebasComponent {
      displayedColumns: string[] = ['name', 'age'];
      dataSource = new MatTableDataSource(ELEMENT_DATA);
    
      applyFilter(filterValue: string) {
        this.dataSource.filter = filterValue.trim().toLowerCase();
      }
    }
    

    This is my HTML code.

    <mat-toolbar color="primary">My full table</mat-toolbar>
    <mat-form-field>
        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
    </mat-form-field>
    <mat-table #table [dataSource]="dataSource">
        <ng-container matColumnDef="name">
            <mat-header-cell *matHeaderCellDef mat-sort-header>Name </mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
        </ng-container>
        <ng-container matColumnDef="age">
            <mat-header-cell *matHeaderCellDef mat-sort-header>Age </mat-header-cell>
            <mat-cell *matCellDef="let element"> {{element.age}} </mat-cell>
        </ng-container>
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="row.toggle(row)">
        </mat-row>
    </mat-table>
    <div *ngIf="dataSource.length === 0">No data</div>