#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.