Как узнать, когда элемент отображался в DOM с использованием * ngFor? - PullRequest
3 голосов
/ 07 июня 2019

Я отображаю список сообщений, используя *ngFor, и хочу применить класс css к элементам, добавленным в коллекцию. после , список был изначально обработан.

т.е.Не нужно применять класс при первоначальной загрузке представления, но только тогда, когда коллекция messages получает новый элемент.

Источник этой коллекции - наблюдаемый из службы, которая может измениться в любое время.

<div *ngFor="let message of thread.messages">
    <div [class.fade-in-text]="threadWasLoaded">
        {{ message.text }}
    </div>
</div>

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

В результате либо класс css всегда применяется ко всем элементам списка, либо я получаю следующую ошибку:

Ошибка: ExpressionChangedAfterItHasBeenCheckedError: Выражение изменилось после его проверки.


this.thread$ = 
    this.storeQuery.getThreadWithMessages(this.threadId)
        .pipe(
            map(t => this.thread = new Thread(t)),
            tap(t => this.threadWasLoaded = true)
        );

Возможно, я задаю не тот вопрос полностью.Пожалуйста, дайте мне знать, если мой общий подход вне базы.: -)

Ответы [ 3 ]

1 голос
/ 07 июня 2019

Я создал рабочий Stackblitz-пример для вас на основе моего комментария: https://stackblitz.com/edit/angular-nn5w2u

Я опустил здесь функцию генерации имени, но она есть в Stackblitz. объекты = [];

  ngAfterViewInit() {
    this.fetchData();
    interval(5000).subscribe(() => this.addItem());

  }

  fetchData() {
    // creates mock data with a delay, simulating backend
    timer(2000).subscribe(() => this.objects = [{name: 'John Doe', initial: true}, {name: 'Marilyn Monroe', initial: true}])
  }

  addItem() {
    this.objects.push({name: this.generateName()});
  }

-

<ng-container *ngIf="objects.length">
<p class *ngFor="let obj of objects" [class.newItem]="!obj.initial">
  {{obj.name}}
</p>
</ng-container>
0 голосов
/ 07 июня 2019

Создайте наблюдаемое с тайм-аутом.

<div *ngFor="let message of thread.messages">
    <div [class.fade-in-text]="delayTrue() | async">
        {{ message.text }}
    </div>
</div>

function delayTrue() {
   return new Observable(s => setTimeout(() => (s.next(true),s.complete()));
}

Удалите все, что вы сделали с threadWasLoaded, и ошибка должна исчезнуть.

0 голосов
/ 07 июня 2019

Является ли класс fade-in-text анимацией? Если старые предметы сохраняют свой класс fade-in-text, это вызовет проблемы? Не могли бы вы обойти это?

Если это так, просто сохраните класс fade-in-text для всех предметов. Только новые предметы получат анимацию. Но Angular может не знать, является ли элемент новым или нет без trackBy в вашем ngFor, поэтому он может удалить / добавить класс к старым элементам, перезапустив их постепенную анимацию.

...