更好地控制Angular渲染

时间:2019-03-01 02:59:54

标签: angular ngrx busyindicator

我有一种很常见的情况:

我显示一个忙于等待的微调框,直到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'

2 个答案:

答案 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中。