Выполнить действие после того, как все * Были отображены записи переменной списка ngFor

#angular

#angular

Вопрос:

В приложении Angular 8 у меня есть элемент контейнера, содержащий *ngFor сгенерированные элементы. У меня есть CSS-свойство контейнера, overflow: auto поскольку я стремлюсь к тому, чтобы он имел фиксированную высоту, не обращая внимания на количество *ngFor сгенерированных в нем элементов.

Я хочу программно прокрутить до нижней части контейнера, выполняемого containerElement.scrollTo(0, containerElement.scrollHeight); после того, как *ngFor все элементы будут сгенерированы, чтобы контейнер containerElement.scrollHeight рассчитал его.

Проблема в том, что если я использую перехват AfterViewInit жизненного цикла, он запускается один раз, но это не гарантирует, что *ngFor элементы будут отрисованы (в моем случае он всегда срабатывает до этого). Если я использую AfterViewChecked перехват, это работает, но он запускается так много раз, что я думаю, что должно быть лучшее решение, где я использую обработчик событий, который запускается ровно один раз, после того, как *ngFor гарантированно было выполнено в DOM.

Спасибо всем, кто подумает над решением этой проблемы!

ОБНОВЛЕНИЕ с помощью этого обходного решения: Из-за отсутствия ответов я решил применить обходной путь. Я сделал что-то вроде следующего: установил id атрибуты для *ngFor сгенерированных элементов и проверил существование последнего в DOM определенное количество раз, после того как записи были извлечены с сервера:

В контроллере

 private loopEntries = [];
private scrollInterval;

async ngOnInit() {
  ...
  this.loopEntries = await this.getFromServer();
  if (typeof this.loopEntries !== 'undefined' amp;amp; this.loopEntries.length) {
    let lastLoopElem = null,
        numTries = 0; // try certain number of times before giving up

    this.scrollInterval = setInterval(() => {
      lastLoopElem = document.querySelector('#index_'   (this.loopEntries.length - 1));
      if (lastLoopElem) { // element is found in the DOM !!!
        const containerElement = document.querySelector('.container');
        containerElement.scrollTo(0, containerElement.scrollHeight);
      }

      if (lastLoopElem || numTries > 10) {
        clearInterval(this.scrollInterval); // clear interval in all the cases
      }
      numTries  ;
    }, 50);
  }
  ...
}

ngOnDestroy() {
  clearInterval(this.scrollInterval); // clear interval on navigate away
}
  

В шаблоне:

 <section class="container">
  <div *ngFor="let item of loopEntries; index as i" [id]="index_'   i">

  </div>
</section>
  

Я знаю, что это немного многословно и халтурно, но я предлагаю это вашему вниманию из-за отсутствия лучшего решения на данный момент. Это похоже на использование setTimeout, но имеет больше шансов на успех, поскольку выполняется несколько раз. Обычно это удается с первой попытки.

Комментарии:

1. Рассматривали ли вы возможность использования небольшой задержки внутри перехвата (т. Е. setTimeout() ) для обеспечения загрузки страницы? Очевидно, что это не было бы полной защитой, но в подавляющем большинстве случаев оно отображалось бы корректно, при условии, что задержка правильно рассчитана по времени… В противном случае вы могли бы использовать реактивное решение, такое как RxJS.

2. Да, @NathanToulbert, setTimeout() это, конечно, первое, о чем можно было подумать, но идея заключалась в том, чтобы изучить любые встроенные решения Angular для достижения этого. В конце концов, если окажется, что другого способа нет, то, как вы указали, я буду использовать observable.