*ngIf 的奇怪行为,但适用于 hidden
Weird behavior with *ngIf but works with hidden
代替 copy-pasting 我的代码,让我分享 stackblitz 中的代码。起作用的两个组件是:
- SearchResultComponent
- 搜索结果表组件
我关注的代码是模板文件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 演示中试用它。
我知道 ngIf
和 hidden
指令之间的区别。 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">
....
代替 copy-pasting 我的代码,让我分享 stackblitz 中的代码。起作用的两个组件是:
- SearchResultComponent
- 搜索结果表组件
我关注的代码是模板文件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 演示中试用它。
我知道 ngIf
和 hidden
指令之间的区别。 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">
....