Angular doesn't automatically display the changes in my array of string

Viewed 492
let signalRServerEndPoint = 'https://localhost:44338';
this.connection = $.hubConnection(signalRServerEndPoint);
this.proxy = this.connection.createHubProxy('MessagesHub');

this.proxy.on("ReceiveMessage", (message) => {
  console.log(message); //LOG IS OKAY
  this.listMessages.push(message); // PUSH IS OKAY
  console.log(this.listMessages); // LOG IS OKAY IS OKAY
});

The listmessages is an array of string[]. Both console.log() works fine, also the this.listMessages.push(message) works fine because the second console.log display the right array of string. But my problem is in my UI it doesn't automatically populate the new listMessages. It will only display the new populated array when I type something in the textbox or when I click a send button again then it display the latest I've sent earlier. Anyone can help me what's wrong with this?

<div *ngFor="let listMessage of listMessages;let indexs = index;">
    <div class="row align-items-center" style="margin-bottom: 5px;" *ngIf="indexs % 2 == 0">
        <div class="col-lg-7">
            <div class="row">
                <img [src]="createImagePath('userphoto/202431775reyes.jpg')" class="avatar avatar-sm rounded-circle" style="margin-left: 20px; max-width: 70px; max-height: 50px;" />
                <div class="card-header bg-gradient-success" style="margin-left: 20px; border-radius: 25px; background-color: #f1f0f0;">
                    <h4 style="margin-bottom: -10px; margin-top: -10px;" class="text-white">{{listMessage}}</h4>
                </div>
            </div>
            <h6 class="text-primary" style="margin-left: 10px;">Anthony Earl Cuartero: 12:00 PM | Aug 13</h6>
        </div>
    </div>
</div>
3 Answers

This is most probably a case of change detection not being triggered because the reference to the variable isn't modified. You could force it using destructuring operator instead of the push. Try replacing the push statement with

this.listMessages = [...this.listMessages, message];

Or you could retain the push statement and trigger change detection manually using Angular ChangeDetectorRef.

import { Component, ChangeDetectorRef } from '@angular/core';

export class AppComponent {
  constructor(private changeDetectorRef: ChangeDetectorRef) { }

this.proxy.on("ReceiveMessage", (message) => {
  this.listMessages.push(message);
  this.changeDetectorRef.detectChanges();
});

the issue is that jquery isn't well integrated with angular so the events aren't triggering change detection... you should ideally find a way to stop using jquery, you can use signalR without it and there are better integrated signalR / angular libraries out there.

in the meantime, this is untested, but I believe it will work if you leverage NgZone to bring it into angular's change detection... something like...

constructor(private ngZone: NgZone) {}

this.proxy.on("ReceiveMessage", (message) => {
  this.ngZone.run(() => {
    console.log(message); //LOG IS OKAY
    this.listMessages.push(message); // PUSH IS OKAY
    console.log(this.listMessages); // LOG IS OKAY IS OKAY
  });
});

you'll probably want to implement some websocket wrapper service that does this for you with all websocket events so you don't need to use NgZone everywhere you use websockets.

You are using push to update Array, so the array reference is same and hence it is not updating the UI, you can create a new Array using array.filter or spread operator. In short you have to create a new array using old array and updated data. Array is a reference type in JavaScript.

Related