Более точный контроль над угловым рендерингом - PullRequest
0 голосов
/ 01 марта 2019

У меня есть то, что, вероятно, должно быть очень распространенным сценарием:

Я отображаю счетчик ожидания занятости, пока состояние NgRx не сигнализирует о завершении операции.

В шаблоне:

<my-loading-spinner *ngIf="loading$ | async"></my-loading-spinner>

В коде компонента:

this.loading$ = store.pipe(select(operationStatus), map(loadingFn));

... где функция loadingFn отображает состояние operationState NgRxзначение в логическое значение.

Данные результата для этого представления загружаются в состояние NgRx прямо рядом с operationStatus в том же вызове в редукторе:

return set(
        STATUS, EntityStatus.loadingSuccess, // the operationState
        myEntityAdapter.addAll(action.payload.tokens, state) // the data
      ) as MyEntityState;

Этот результатdata - это длинный список объектов, который проходит сортировку в компоненте, а затем обрабатывается с помощью *ngFor с нетривиальным содержимым.

Поэтому неудивительно, что у меня возникает проблема: счетчик ожидания занятости заметно уходит до того, как на экране появляется таблица отображаемых данных.

Есть ли какой-либо тип "некоторых специфических данных"?-has-закончено-рендеринг "событие, которое можно отслеживать, чтобы я мог заставить мой счетчик ожидания заняты оставаться до тех пор, пока таблица данных не будет полностью обработана?

2019.03.01 Обновление

Я попробовал подход, предложенный @ConnorsFan: я изменил свой шаблон, чтобы использовать новый ненаблюдаемый *ngIf="viewLoading", инициализированный как public viewLoading = true; Затем в теле подписки я просто установил его как ложное:

this.dataRows.changes.subscribe(() => {
    this.viewLoading = false;
});

Я попробовал этот подход, но он не имел значения;прядильщик все еще был спрятан преждевременно.Возможно, я не правильно применил рецепт?Я должен отметить, что это также приводило к ошибке времени выполнения, всегда вызывающему ExpressionChangedAfterItHasBeenCheckedError ( Предыдущее значение: 'ngIf: true'. Текущее значение: 'ngIf: false' )

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Я думаю, что @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$.Это удалит отображение после того, как QueryList выдаст сообщение об изменении.Поэтому, когда список показан, он должен уже существовать в полностью отрисованном DOM.

0 голосов
/ 01 марта 2019

Если у вас есть элемент, сгенерированный в цикле 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;
    });
  }

}
...