74

I am using this code

 <mat-table #table [dataSource]="dataSource" matSort >
  <ng-container matColumnDef="tache">
    <mat-header-cell *matHeaderCellDef mat-sort-header> tâche </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.tache}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="outil">
    <mat-header-cell *matHeaderCellDef mat-sort-header> outil </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.outil}} </mat-cell>
  </ng-container>  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selection.toggle(row)">
  </mat-row>
</mat-table>

So, how to show empty message "No Record found" in data table.

2
  • 1
    Can you elaborate on what you mean by data not found? Commented May 3, 2018 at 8:03
  • If datasource is empty I have to display 'No records found message' Commented May 3, 2018 at 8:13

20 Answers 20

126

With Angular Material 10 or above If you want to show a message when not data matches the filter, you can use the *matNoDataRow directive.

 <tr class="mat-row" *matNoDataRow>
  <td class="mat-cell" [attr.colspan]="displayedColumns.length">
    No data matching the filter.
  </td>
</tr>
Sign up to request clarification or add additional context in comments.

5 Comments

If using <mat-table> instead of a <table> then just drop <div *matNoDataRow>No data</div> inside <mat-table>. Though it still won't help hiding <mat-paginator> if you've got one
You can have a better colspan with: <td [colSpan]="displayedColumns.length">
Does anyone know why using <mat-row> and <mat-cell> doesn't work with the *matNoDataRow directive but using <tr> and <td> does?
You need to make use of <mat-table> instead of a <table> to use <mat-row> and <mat-cell>.
@fix is right. <mat-row> and <mat-cell> doesn't work for *matNoDataRow when using <mat-table> at least in v15. Seems like a bug.
28

It's like bugs is saying, you can just use *ngIf. Compare these two tables here:

https://stackblitz.com/edit/angular-w9ckf8

<mat-toolbar color="primary">My empty table</mat-toolbar>

<mat-table #table [dataSource]="dataSourceEmpty" matSort *ngIf="dataSourceEmpty.length > 0">
    <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="dataSourceEmpty.length === 0">No records found</div>

<hr>

<mat-toolbar color="primary">My full table</mat-toolbar>

<mat-table #table [dataSource]="dataSource" matSort *ngIf="dataSource.length > 0">
    <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>

TS with data:

displayedColumns = ['Name', 'Age']
dataSource = [{name:'Sara',age:17}, {name: 'John', age: 20}]
dataSourceEmpty = []

10 Comments

thx i fixed it with <mat-toolbar color="primary" *ngIf="empty">No records found message</mat-toolbar>
Cool, glad I could help
The example relies on a simple datasource that is a JS array. What do you recommend when using an instance of abstract class DataSource<T> that Angular provides in @angular/cdk/collections/typings/data-source.d.ts ?
You will get an undefined error when you try to set dataSource.sort = matSort, since @ViewChild(MatSort) sort: MatSort; will be undefined until the table is available. If you remove the matSort directive from the table, this would be ok. You could also put your put your table inside another component and handle the "no results" in the parent component, so that the table, datasource, and matsort are all initiated at once IF there is data.
@LeonardoRick If you want to keep the columns, remove the line *ngIf="dataSourceEmpty.length > 0" on line 8 in my example.
|
23

You can put it in the footer row this way:

Column definition:

<ng-container matColumnDef="noRecord">
      <td mat-footer-cell *matFooterCellDef>No records found.</td>
</ng-container>

Footer row definition:

<ng-template [ngIf]="dataSource.data.length === 0">
    <tr mat-footer-row *matFooterRowDef="['noRecord']"></tr>
</ng-template>

3 Comments

This looks like a very promising solution because the footer row should be styled nicely to match, but it's difficult to assemble from these pieces, would you please show the complete HTML template?
@chrisinmtown:Just put this inside e.g: <mat-table> <ng-container matColumnDef="noRecord"> <td mat-footer-cell *matFooterCellDef>No records found.</td> </ng-container> <ng-template [ngIf]="dataSource.data.length === 0"> <tr mat-footer-row *matFooterRowDef="['noRecord']"></tr> </ng-template> </mat-table>
I also tried this solution but it doesn't work for me. When I delete an object and the table becomes empty the row doesn't show up. When the I reload the page then it shows up, but while adding an object the row doesn't vanish. It's very strange. Can anyone provide a working exmaple for this?
19

If you console.log dataSource, you will see the following: dataSource example

It is not the dataSource itself that is the array, but dataSource.data. dataSource is actually a class that has a property data that contains what you pass into MatTableDataSource (https://github.com/angular/material2/blob/master/src/lib/table/table-data-source.ts) Therefore, this is what you should be using for your *ngIf statement.

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

Hope this helps!

2 Comments

Just in case if anyone is using filter then you need to check for data.filteredData.length === 0
this is not working for me! html fails to fetch inner .data property .data.length blows code. even after this this.dataSource = new MatTableDataSource(); this.dataSource.data = [];
10

There are two ways to show error message in html

1st method using If method

<div *ngIf="dataSource.length">
  <mat-table #table [dataSource]="dataSource" matSort >
  <ng-container matColumnDef="tache">
    <mat-header-cell *matHeaderCellDef mat-sort-header> tâche </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.tache}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="outil">
    <mat-header-cell *matHeaderCellDef mat-sort-header> outil </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.outil}} </mat-cell>
  </ng-container>  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selection.toggle(row)">
  </mat-row>
</mat-table>
</div>

<div *ngIf="!dataSource.length">
No Record found
</div>

2nd Method Using If else

<div *ngIf="dataSource.length; else noRecord">
  <mat-table #table [dataSource]="dataSource" matSort >
  <ng-container matColumnDef="tache">
    <mat-header-cell *matHeaderCellDef mat-sort-header> tâche </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.tache}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="outil">
    <mat-header-cell *matHeaderCellDef mat-sort-header> outil </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.outil}} </mat-cell>
  </ng-container>  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selection.toggle(row)">
  </mat-row>
</mat-table>
</div>

<ng-template #noRecord>
 <div>
  No Record found
  </div>
</ng-template>

Comments

8
<mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':!(listData!=null && listData.filteredData.length==0)}"></mat-footer-row>

I was able to solve the problem by doing this. hide is a custom css

.hide{
    display:none;
} 

2 Comments

<mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':!(listData!=null && listData.filteredData.length==0)}"></mat-footer-row>
great solution but rather than hiding <tr> you can make the array dynamic matFooterRowDef="['noData']" and add the column name in case only when you want to display the NOT FOUND message
6

Step #0

In ts

  dataSource: any = new MatTableDataSource()

Step #1

      <table [dataSource]="dataSource">

        <ng-container matColumnDef="nodata">
          <td mat-footer-row *matFooterCellDef [colSpan]="displayedColumns.length" 
          style="text-align: center;">No Data Available</td>
        </ng-container>

       <tr mat-footer-row 
         [hidden]="dataSource.data.length >0"
        *matFooterRowDef="['nodata']">
       </tr>

     </table>

Comments

5

In your component-name.component.html:

<div class="mat-elevation-z8">
    <mat-table [dataSource]="listData" matSort>
        <ng-container matColumnDef="fullName">
            <mat-header-cell *matHeaderCellDef mat-sort-header>Full Name</mat-header-cell>
            <mat-cell *matCellDef="let element">{{element.fullName}}</mat-cell>
        </ng-container>
        ...
        ...
        <ng-container matColumnDef="noData">
            <mat-footer-cell *matFooterCellDef colspan="6">
                No data.
            </mat-footer-cell>
        </ng-container>

        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>

        <mat-footer-row *matFooterRowDef="['noData']" [ngClass]="{'hide':!(listData!=null && listData.data.length==0)}"></mat-footer-row>
    </mat-table>
    <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]="5" showFirstLastButtons></mat-paginator>
</div>

In your style.scss or component-name.component.scss define .hide class

.hide { display: none; }

and that's all :)

1 Comment

This works for me. I just changed to check by dataSource.filteredData.length
3

In newer Angular versions don't forget datasource.data if your datasource is of type MatTableDataSource.

Example:

In the TypeScript file:

// ...
datasource = new MatTableDataSource<object>([]);
// ...

And in the HTML file:

<div *ngIf="datasource.data.length > 0"> 
  <!--Show the table.-->
</div>

<div *ngIf="datasource.data.length === 0">
 <!--Show table is empty message. -->
</div>

1 Comment

it is failing for me. Cannot read properties of null (reading 'length')
2

If anyone uses filter with dataSource, you should watch for dataSource.filteredData.length.

i.e.

if (this.dataSource.filteredData.length < 1) {
  this.presentDialog();
}

or

<div class="container" *ngIf="dataSource.filteredData.length < 1">
    // Your message here...
</div>

Comments

2

Just as PLPeeters said If you are using Angluar Material >= 10 or more, then you can show a message when no data matches the filter, by using the *matNoDataRow directive, which looks something like this :

 <tr class="mat-row" *matNoDataRow>
  <td class="mat-cell" [attr.colspan]="displayedColumns.length">
    No data matching the filter.
  </td>
</tr>

If you are using Angular Material <10 Then You can use the following code to show data after filtering, if no data is available you can show the row with the text :

      <!-- No Data Found -->
      <ng-container matColumnDef="noDataFound" >
        <td mat-footer-cell *matFooterCellDef colspan="7" [hidden]="dataSource?.filteredData?.length!=0">
          No records found 
        </td>
      </ng-container>

Comments

1

You can simply use the *ngIf directive to check if dataSource is not empty.

 <mat-table *ngIf="dataSource.length > 0" #table [dataSource]="dataSource" matSort >
  <ng-container matColumnDef="tache">
    <mat-header-cell *matHeaderCellDef mat-sort-header> tâche </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.tache}} </mat-cell>
  </ng-container>

  <ng-container matColumnDef="outil">
    <mat-header-cell *matHeaderCellDef mat-sort-header> outil </mat-header-cell>
    <mat-cell *matCellDef="let element"> {{element.outil}} </mat-cell>
  </ng-container>  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selection.toggle(row)">
  </mat-row>
</mat-table>

<p *ngIf="dataSource.length === 0">No records found</p>

1 Comment

Can you edit your question to post your dataSource?
1

You can add a condition on your dataSource directly without having to access the data or its length:

<div *ngIf="!yourDataSource" class="alert alert-primary" role="alert">No data </div>

Comments

1

You can use HTML hidden attribute to achieve same thing

<tr [hidden]="dataSource.data.length > 0" mat-footer-row *matFooterRowDef="['noRecord']" ></tr>

Comments

0

In .ts file

if (this.dataSource.length == 0) {
    this.noDataMessage = true;
} else {
    this.noDataMessage = false;
}

In .html file

<div *ngIf="noDataMessage">
    <p>{{ 'label.DataNotAvailable' | translate }}</p>
</div>

Comments

0

For anyone having the option to do this in the Footer, I have been able to do this by doing following steps in Angular 6/7/8:

1) In your [ComponentName].component.html

<table mat-table [dataSource]="dataSourceTable">
    <ng-container matColumnDef="columneName">
            <th mat-header-cell *matHeaderCellDef> Name </th>
            <td mat-cell *matCellDef="let element"> {{element.columnname}} </td>
            <td mat-footer-cell *matFooterCellDef>
                <!-- Display a download button in the footer when data is available-->
                <button mat-raised-button color="primary" 
*ngIf="dataSourceTable.data.length > 0">Download</button>
                <!--Below code is displayed when there is no data-->
                <a mat-button *ngIf="dataSourceTable.data.length === 0">No Data 
Found</a>
            </td>
        </ng-container>
        <!--Below Lines of code generates Header, Row and footer for your table  -->
        <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true;"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;">
        </tr>
        <tr mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></tr>
    </table>

Comments

0

this worked for me:

<ng-container matColumnDef="noRecords">
  <td mat-footer-cell *matFooterCellDef>
    No records found
  </td>
</ng-container>

<tr mat-footer-row *matFooterRowDef="!dataSource.filteredData.length ? ['noRecords'] : []" colspan="2"></tr>

Also note that it's possible you have to add a <td mat-footer-cell *matFooterCellDef></td> for every row if you already use the footer.

1 Comment

Nice solution, but colspan should be set on the <td> element. You can add it with: <td mat-footer-cell *matFooterCellDef [colSpan]="displayedColumns.length">. Nevertheless, now the best approach is the one proposed by @rrr: stackoverflow.com/a/63185957/690691
0

My solution does not alter the footer, and shows the message inside of the actual table by using CSS and adding a box :before the footer:

First some CSS:

td.no-content {
  padding-top: 7rem;
}

td.no-content:before {
  content: attr(data-empty-message);
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  text-align: center;
  padding: 3rem 0 3rem 0;
  background-color: white;
}

Then add the no-content class to the footer TD when nothing is showing:

<td mat-footer-cell *matFooterCellDef 
    [class.no-content]="dataSource.filteredData.length === 0" 
    data-empty-message="Nothing found..."
>

Comments

0

I was getting a runtime error "Cannot read property 'length' of undefined" if the array was null. Solved it by first checking the null value, and if true it does not proceed to the length test, thus not causing the error. i.e.

<tr *ngFor="let category of _projectCategories">
        <td>
            {{ category.name }}
        </td>
        <td>
            {{ category.description }}
        </td>
        <td>
            {{ category.group }}
        </td>
        <td>
            <i class="nc-icon" [class.nc-check-2]="category.active"
                [class.nc-simple-remove]="!category.active"></i>
        </td>
    </tr>
    <tr *ngIf="(_projectCategories==null) || (_projectCategories.length == 0)">
        <td colspan="2">
            Project currently has no categories.
        </td>
    </tr>

Comments

0

Inside your table add this

   <tr class="mat-row" *matNoDataRow>
        <td class="mat-cell" colspan="9999">No Transactions yet!</td>
    </tr>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.