如何知道何时使用* ngFor在DOM中渲染了项目?

时间:2019-06-07 18:09:04

标签: angular rxjs rxjs6

我正在使用*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)
        );

我可能完全是在问错问题。请让我知道我的整体方法是否不合时宜。 :-)

4 个答案:

答案 0 :(得分:1)

基于我的评论,我为您创建了一个有效的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>

答案 1 :(得分:1)

我知道这是通过另一种方式解决的,但是对于将来的发现者来说,这是对pairwise()运算符执行增量运算的完美用例:

  public  thread$ = this.dataService.thread$.pipe(
    startWith(null), // pairwise requires 2 emissions so we start it with a null
    pairwise(), // emit the last value and the current value in pairs
    map(([oThread, nThread]) => {
      if (oThread) { // only do this if there was a prior emission
        nThread.messages = nThread.messages.map(message => { // map the messages
          let isNew = false;
          if (!oThread.messages.find(m => m.id === message.id)) {
            // if they're not in the old array, they're new
            isNew = true;
          };
          return Object.assign({},message, {isNew});
        });
      }
      return nThread.messages;
    })
  );

和闪电战:https://stackblitz.com/edit/angular-problem-preventing-animation-on-page-load-aybwz4?file=src/app/app.component.ts

答案 2 :(得分:0)

fade-in-text类是动画吗?如果旧项目保留其fade-in-text类,是否会引起问题?您能解决这个问题吗?

如果是这种情况,只需在所有项目上保留fade-in-text类。只有新项目才能获得动画。但是Angular可能不知道在ngFor中没有trackBy的项目是否是新项目,因此它可能会将类删除/添加回旧项目,从而重新启动其淡入动画。

答案 3 :(得分:0)

创建一个带有超时的观察对象。

<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所做的所有操作,错误就会消失。