I want to use ngFor
with async
data (loaded from API) and trackBy
to improve performance and to update list without DOM flashing/flickering when data updates.
If data is static - everything works fine. But when i try to use data loaded from API - trackBy
doesn't work.
from API: https://stackblitz.com/edit/angular-hx4p39
static data: https://stackblitz.com/edit/angular-myb6vj
export class AppComponent {
constructor(private http: HttpClient){}
comments$: Observable<Comment[]> = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=5`);
add() {
this.comments$ = this.http.get<Comment[]>(`https://jsonplaceholder.typicode.com/comments?_start=0&_limit=6`);
}
edit() {
this.comments$ = this.comments$.pipe(
map(comments => {
comments.map( comment => {
if(comment.id === 5){ comment.name = 'edit'; }
return comment;
});
return comments;
})
);
}
itemTrackBy(index: number, item: Comment) {
return item.id;
}
}
interface Comment {
postId;
id;
email;
name;
body;
}
<button (click)="add()">Make 6</button>
OR
<button (click)="edit()">edit 5-th element</button>
<ul>
<li *ngFor="let comment of (comments$ | async); trackBy: itemTrackBy">
{{comment.id}} - {{comment.name}}
</li>
</ul>
This happens because you are changing your observable for another observable instance. ngFor detects that an re-render the dom when a new observable is set . The correct way to work is to not set a new observable, is to just push new items on the observable .
Here is an stackblitz example that applies this approach, you will see that the dom is not re-rendered: https://stackblitz.com/edit/angular-wslaz7
I don't know why the example with the static data doesn't re-render the dom, maybe is a side effect when the whole operation is 'sync', since if I add a delay() after the of() like:
this.episodes = of([
{id: 1, name: "name1"},
{id: 2, name: "name2"}
]).pipe(delay(100));
you will see that it will re-render the items.
We could ask angular team why it doesn't re-render when no delay() is applied, I have no idea.
Hope this helps!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.