Skip to content

How to improve rendering performance with *ngFor in Angular

I am creating a chat app, and performance is slow when a lot of messages are sent at once. The messages show up but the UI becomes unresponsive for a while. Here is a simplified version of the code and how can I fix this?

HTML:

<div class="message-notification" *ngFor="let newMessage of chatMessages"; trackBy: trackByMsgs>
   <custom-notification [incomingChat]="newMessage" (dismissedEvent)="onDismiss($event)" (closedEvent)="onNotifcationClose($event)"></custom-notification>
</div>

TS:

newChatMessages: any[];

constructor(private chatService: ChatService) {}

 ngOnInit() {
    this.chatService.chatMsg.subscribe((msg:any) => {
    if (msg) {
       this.activatePopup(msg);
    }
  }

  activatePopup(message) {
    if (message.msgId !== null && message.title !== null) {
       this.setTitle(message);

    //If popup is already open then do not display a duplicate popup for the same message
         let index = this.isPopupOpen(message);
         if (index === -1) {
           newChatMessages.push(message);
         }else {
           newChatMessages[index] = message;
         }
     }
  }

   trackByMsgs(index:number, msg:any) {
     return msg.msgId && msg.title;
   }

   isPopUpOpen(message){
     let index = -1;
     if (this.newChatMessages){
      index = this.newChatMessages.findIndex(
         msg => msg.id === message.id && msg.title === message.title);
      }
    return index;
   }

Answer

The best in your case is to control the angular change detection manually by using OnPush Change Detection Strategy. You should carefully use it, cause when it’s on, angular will detect changes only if onChanges lifecycle is been triggered or async pipe has received a new value. It also applies to all the component children.

Then you would need to detect the changes manually by injecting the ChangeDetectorRef in your component and call the method detectChanges on it each time you want to apply your data changes to your dom.
Read this article for better understanding

Another interesting article for improving the performance of your angular app https://medium.com/swlh/angular-performance-optimization-techniques-5b7ca0808f8b

Using trackBy helps angular to memorize the loaded elements in the ngFor and update only the changed once on change detection. But your trackByMsgs returns a boolean which is not what it should return. If you adjust your trackBy to return a unique key like msg.msgId or the index of the item, you might see a difference.