Angular component not updating when service returns

1.1k Views Asked by At

I have an Angular component with badges on some icons. The numbers for the badges come from an api that I call when entering the page, in ionViewWillEnter(). When the api returns, the result is assigned to a local variable, that's then referenced in the markup. In Chrome desktop, it all works fine. In Chrome android, the badge doesn't appear until I touch the screen. Why might changes to a local variable not immediately be reflected in the markup? I've tried putting the whole routine in an NgZone, but to no avail. I've also worked through the suggestions in this post, ChangeDetectorRef.detectChanges() and markForCheck(), ApplicationRef.tick()

Update 2: The data gets passed down to a child component, as an object, then again to a grandchild, as a primitive, via @Input properties. If I also display the info directly in the markup of the parent, then both the parent and grandchild component update as expected when the call to the service returns. If I try to trick the system by putting display:none on the parent, my problem returns and I have to touch the screen to see the change in the child.

Here is my .ts code...

// declaration
pastilles: Pastilles = { nbFraisCarte: 0, nbFraisRefuse: 0, nbJustificatifs: 0 };

async ionViewWillEnter(){
  this.ngZone.run(async () => {
    await this._myService
      .pastilles()
      .toPromise()
      .then((resp) => {
        if ((resp.status = 'success')) {
          this.pastilles= resp.sData;
        }
      });
  });
}

In the child component, I have...

@Input()
pastilles: Pastilles;

then in the markup...

<tne-round-button
  (click)="createFraisFrom.emit('justificatif')"
  icon="image"
  [pastille]="pastilles.nbJustificatifs"
></tne-round-button>

then in the tne-round-button grandchild, much the same thing...

@Input()
pastille: number;

and markup...

<div class="pastille" *ngIf="pastille">
  <div class="pastille-text">{{ pastille }}</div>
</div>

What have I missed?

2

There are 2 best solutions below

2
On BEST ANSWER

Ok so this nearly broke my heart. It turns out the issue was that the data was used in a child component, and the update was simply never made it to the child. The workaround was to also use the data directly in the template of the component that receives it, so triggering the refresh. I have added an invisible div to the parent template, like this...

<div style="visibility: hidden;">{{pastilles.nbJustificatifs}}</div>

...and the badges, still handled in my child component, magically appear. It's ugly, but I'm moving on!

2
On

Because pastilles is an object, and Angular can't tell that the object has changed because it's reference is still the same, try doing this.

this.pastilles = { ...resp.sData }

or this

Object.assign(this.pastilles, resp.sData);

I would try them out of the NgZone. Let me know if it works!