我有一种很常见的情况:
我显示一个忙于等待的微调框,直到NgRx状态表示操作完成。
在模板中:
<my-loading-spinner *ngIf="loading$ | async"></my-loading-spinner>
在组件支持代码中:
this.loading$ = store.pipe(select(operationStatus), map(loadingFn));
...,其中loadingFn
函数将operationState
NgRx状态值映射到布尔值。
此视图的结果数据在化简器中的同一调用中就紧随operationStatus
加载到NgRx状态:
return set(
STATUS, EntityStatus.loadingSuccess, // the operationState
myEntityAdapter.addAll(action.payload.tokens, state) // the data
) as MyEntityState;
此结果数据是一个冗长的对象列表,它在组件中经过排序,然后通过*ngFor
呈现不平凡的内容。
因此出现我的问题也就不足为奇了:忙碌的微调器在呈现的数据表出现在屏幕上之前就消失了。
是否可以监视任何类型的“某些特定数据已完成渲染”事件,以便我可以让忙碌的微调框一直停留到数据表完全渲染为止?
2019.03.01更新
我尝试了@ConnorsFan建议的方法:我更改了模板,以使用新的不可观察的*ngIf="viewLoading"
初始化为public viewLoading = true;
,然后在订阅正文中将其设置为false:
this.dataRows.changes.subscribe(() => {
this.viewLoading = false;
});
我尝试了这种方法,但是没有改变。旋转器仍被过早隐藏。也许我没有正确地应用食谱?我应该注意,这也会引发运行时错误,总是具有挑战性的ExpressionChangedAfterItHasBeenCheckedError
(上一个值:'ngIf:true'。当前值:'ngIf:false')
答案 0 :(得分:1)
当您通过ngFor
循环生成元素时:
<div #dataRow *ngFor="let item of items"> ... </div>
您可以使用QueryList
获取ViewChildren
元素,并通过订阅QueryList.changes
事件来通知元素已渲染:
import { Component, ViewChildren, QueryList, ElementRef, AfterViewInit } from '@angular/core';
...
export class MyComponent {
@ViewChildren("dataRow") dataRows: QueryList<ElementRef>;
dataRowsRendered: boolean;
ngAfterViewInit() {
this.dataRows.changes.subscribe(() => {
// Do something after the data rows have been rendered
console.log(`${this.dataRows.length} data rows have been rendered`);
this.dataRowsRendered = true;
});
}
}
答案 1 :(得分:0)
我认为@ConnorsFan是正确的答案。我没想到要使用@ViewChildren()
。
您可以修改他的答案以更新可观察到的loading$
。
@ViewChildren("dataRow") dataRows: QueryList<ElementRef>;
this.loading$ = combineLatest(
store.pipe(select(operationStatus), map(loadingFn)),
this.dataRows.changes.pipe(mapTo(this.dataRows.length === 0)
).pipe(map(([loading,rows])=>loading || rows));
我还建议在样式display: none
加载时将样式ngFor
添加到loading$
元素中,然后从Get-ChildItem
开始将其删除。这将在QueryList发出已更改的显示 后删除。因此,当显示列表时,它应该已经存在于完全呈现的DOM中。