Sнаđошƒаӽ
Sнаđошƒаӽ

Reputation: 17562

Weird behavior with *ngIf but works with hidden

Instead of copy-pasting my codes, let me share the code in stackblitz. The two components in action are:

  1. SearchResultComponent
  2. SearchResultTableComponent

The code that I am concerned with is the template file search-result.component.html, and here is the content:

<div class="content-container">
  <button mat-raised-button color="primary" (click)="onLoadClick()">Load</button>
  <button mat-raised-button color="primary" class="nop-button">NOP button</button>

  <div class="table-container">
    <!-- Does not work -->
    <app-search-result-table *ngIf="searchResult.length" [searchResult]="searchResult"></app-search-result-table>

    <!-- Works -->
    <!-- <app-search-result-table [hidden]="!searchResult.length" [searchResult]="searchResult"></app-search-result-table> -->
  </div>
</div>

What I intend to do is hide the table when the searchResult is empty (initially it is indeed empty), and show it only when it has at least one data row (clicking the "Load" button does that). So I expect it to work by using *ngIf="searchResult.length" but it does not work as expected. Instead what happens is, when I click the "Load" button the first time, it shows the table headers but no data row is displayed (in my actual app, the data on clicking "Load" comes from API, but for demo I am randomly taking elements from an array, and making an observable using the of operator). The data rows however show up when any event occurs that triggers a view update to be triggered - clicking anywhere else in the page or clicking the "NOP button" (it actually is a no-op button) causes the table to show the data rows. Subsequent clicking of the "Load" button causes it to work as expected. But, when I use the hidden directive it always works as expected, including the first time. The line is there in my template file and you can uncomment it (and comment out the ngIf line) and try it out in stackblitz demo I linked.

I know the difference between ngIf and hidden directive. This article explains it in great detail. I also studied this SO post but my situation is different from that one.

What is perplexing to me is why does the table only show the header rows when I click the "Load" button the first time, and then full table is displayed on the next DOM update when using the *ngIf approach?

Upvotes: 1

Views: 739

Answers (1)

Poul Kruijt
Poul Kruijt

Reputation: 71901

You are not using the dataSource input on the mat-table, so no change detection is triggered for the table. You can change your search-result-table to:

@Component({
  selector: 'app-search-result-table',
  templateUrl: './search-result-table.component.html',
  styleUrls: ['./search-result-table.component.css']
})
export class SearchResultTableComponent implements OnChanges {
  @Input() searchResult: UserInfo[] = [];

  readonly dataSource = new MatTableDataSource<UserInfo>([]);
  
  columnNames: string[] = ['firstName', 'lastName', 'email'];

  ngOnChanges(changes: SimpleChanges) {
    if (changes.searchResult) {
      this.dataSource.data = this.searchResult;
    }
  }
}

with as template:

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

working example

Upvotes: 2

Related Questions