angularpromise

Angular - Update HTML when promise is resolved


I have a problem with Angular and Promises I don't understand.

This is my html:

<div>Is Ready? {{isReady}}</div>
<div *ngIf="isReady">Show this</div>
<div *ngIf="!isReady">Show that</div>

This is my TS file:

isReady: boolean = false;

constructor(
 private myService: MyService){
 await this.giveMeSlowData();
}

async giveMeSlowData() : Promise<void>{
 console.log(await this.myService.getResult());
 this.isReady = await this.myService.getResult();
}

Usually everything in this {{}} in HTML changes as soon as the variable in TS file. But not now. I can see console log after 5-6 seconds, but the HTML doesn't change. Why?

Thanks anyone!


Solution

  • There are a few reasons why this never completes yet you get your console log.

    Actual problem

    You have an async method that never returns anything. That leaves the Promise hanging forever. Since await is called on the hung Promise in the constructor, the component will never finish initializing. You can test this by adding a log statement in an ngOnInit.

    Recommendations

    1. I would strong encourage you to switch to using an Observable as that is the standard practice in Angular world. A lot of things with component destruction is handled automatically for you that way. You can even do this without needing to change any logic of MyService which can be convenient if that must remain as a Promise-based class.

    2. All initialization logic should be handled in an ngOnInit method, not in the constructor.

    3. I would encourage you to switch to using the async pipe in the template on all of this.

    Solution

    Here's how that all would come together.

    slow-data.component.ts:

    isReady: Subject<boolean> = new BehaviorSubject(false);
    
    constructor(
     private myService: MyService,
    ) {
    }
    
    ngOnInit(): void {
      giveMeSlowData();
    }
    
    giveMeSlowData(): void {
      from(this.myService.getResult()).subscribe(isReady);
    }
    

    slow-data.component.html

    <div>Is Ready? {{isReady | async}}</div>
    <div *ngIf="isReady | async">Show this</div>
    <div *ngIf="!(isReady | async)">Show that</div>