我正在使用*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)
);
我可能完全是在问错问题。请让我知道我的整体方法是否不合时宜。 :-)
答案 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;
})
);
答案 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
所做的所有操作,错误就会消失。