Search code examples
angularionic-frameworkangular-changedetection

Angular component not updating when service returns


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?


Solution

  • 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 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!