Iñigo
Iñigo

Reputation: 2016

MatPaginator unexpected behaviour inside ngIf?

STACKBLITZ DEMO

I have a material table as following:

<table mat-table [dataSource]="dataSource" >
    ... Rows ...
    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>  
<mat-paginator #MatPaginator [pageSizeOptions]="[4]" showFirstLastButtons></mat-paginator>

I need the table to be hidden when the variable info is false.


  1. Attempt 1:
<table *ngIf="info" mat-table [dataSource]="dataSource" >

It works fine but the pagination does not work when info is true and all rows are displayed on the first page.


  1. Attempt 2:
<table [hidden]="!info" mat-table [dataSource]="dataSource" >

Makes the pagination work, but when info is false the table is still displayed with no results.


  1. Attempt 3:

Tried to sourround the whole table with a div and apply *ngIf to the div. Result: Same problem as in first attempt.

Tried to apply [hidden] to the div but still not hidding.


  1. EDIT: Attempt 4:

Applied directly to the envolving div css style="display:none" and getting the same result as in attempt 3, the table is shown even if it has no values.


Any idea on how to hide the table when info is false and show it when info is true with a working pagination?

Thanks!

Upvotes: 2

Views: 1992

Answers (5)

Kaleb Dalla Pria
Kaleb Dalla Pria

Reputation: 69

I had the same problem because I was using the *ngIf and async pipe in my template and pagination was not working. After some research I was able to make it work using the @ViewChild annotation and a set function so I decided to share my complete solution here :)

The hidden solution propose by other answers didn't work for me.

In my component.ts file:

constructor(private cdRef: ChangeDetectorRef) { }

  private paginator: MatPaginator;
  /*
   We are using @ViewChild because of the ngIf with async pipe on the template
   When the data is emmited for the first time from the observable, we need to bind the
   pagination component with the datasource. This can be achieved with the code bellow.
  */
  @ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
    if(mp) {
      this.paginator = mp;
      this.dataSource = new MatTableDataSource<any>(your_data);
      this.dataSource.paginator = this.paginator;
      this.cdRef.detectChanges();
     }
   }

and in my template file:

// my observable with the async pipe
  <div *ngIf="raceList$ | async as races">
    <div class="mat-table-width">
      <table mat-table [dataSource]="dataSource">
      ...
      </table>
      <mat-paginator [pageSizeOptions]="[10, 20, 30]"
                      showFirstLastButtons
                      aria-label="select page of races">
      </mat-paginator>
    </div>
  </div>

With this solution I was able to display the data in the table and make pagination work.

Upvotes: 0

Jeevana
Jeevana

Reputation: 169

Angular 8 solution:

[hidden] can be used instead of *ngIf and activation of the tab can be done using CSS properties.

 .tableClass .mat-tab-group.mat-primary .mat-ink-bar {
          width: 160px !important;
        }
<div [hidden]="true" class="tableClass">
     <mat-tab-group>
        <mat-tab label="Tab1">
        </mat-tab>
        <mat-tab label="Tab2">
        </mat-tab>
     </mat-tab-group>
</div>

Upvotes: 0

Jorge Mussato
Jorge Mussato

Reputation: 2524

You can't put the paginator inside a ngIf, otherwise, when you set this.dataSource.paginator = this.paginator, this.paginator is undefined. There is a solution if you REALLY want to ngIf it (tell me if it is realy necessary), but I recommend changing it to hidden instead.

Upvotes: 0

dasunse
dasunse

Reputation: 3089

Use this way

 [hidden]="true"

<div [hidden]="true" >
  <table mat-table [dataSource]="dataSource" >
      <ng-container matColumnDef="test">
        <th mat-header-cell *matHeaderCellDef> Test. </th>
          <td mat-cell *matCellDef="let exp"> {{exp}} </td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>  
  <mat-paginator #MatPaginator [pageSizeOptions]="[2, 4, 6]" showFirstLastButtons> 
  </mat-paginator>
<div>

stackblitz demo

make sure to change your condition in [hidden]

Upvotes: 1

jitender
jitender

Reputation: 10429

you can use ngClass to add dynamic class and use that class to hide the table like

[ngClass]="{'hidden': !info}"

and in your style.css

.hidden{
display:none;
}

demo

Upvotes: 0

Related Questions