*ngIf 的奇怪行为,但适用于 hidden

Weird behavior with *ngIf but works with hidden

代替 copy-pasting 我的代码,让我分享 stackblitz 中的代码。起作用的两个组件是:

  1. SearchResultComponent
  2. 搜索结果表组件

我关注的代码是模板文件search-result.component.html,这里是内容:

<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>

我打算做的是当searchResult为空时隐藏table(一开始它确实是空的),只有当它至少有一个数据行时才显示它(点击“加载”按钮就是这样做的)。所以我希望它可以通过使用 *ngIf="searchResult.length" 来工作,但它没有按预期工作。相反,当我第一次点击“加载”按钮时,它显示 table headers 但没有显示数据行(在我的实际应用程序中,点击“加载”的数据来自 API,但为了演示,我随机从数组中获取元素,并使用 of 运算符进行观察)。但是,当发生任何触发视图更新的事件时,数据行就会显示出来——单击页面中的任何其他位置或单击“NOP 按钮”(它实际上是一个 no-op 按钮)会导致 table 来显示数据行。随后单击“加载”按钮会使其按预期工作。但是,当我使用 hidden 指令时,它总是按预期工作,包括第一次。该行在我的模板文件中,您可以取消注释(并注释掉 ngIf 行)并在我链接的 stackblitz 演示中试用它。

我知道 ngIfhidden 指令之间的区别。 This article explains it in great detail. I also studied this SO post 但是我的情况和那个不一样。

让我很困惑的是为什么第一次点击“加载”按钮时table只显示header行,然后显示完整的table在使用 *ngIf 方法时的下一个 DOM 更新?

您没有在 mat-table 上使用 dataSource 输入,因此不会触发 table 的更改检测。您可以将 search-result-table 更改为:

@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;
    }
  }
}

作为模板:

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

working example