2

For the status property declared and populated like below:

  public status:Promise<String>;

  constructor() {
    this.status = this.getStatus();
  }

  public getStatus():Promise<String>{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
          resolve('stable');
        },2500);
    });
   }

could somebody explain how the below async pipe works?

    <span *ngIf="status|async">
        {{ status|async }}
    </span>
1
  • The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. In your code async pipe will trigger when the promise (this.status) is completed with the value stable, Your promise is completed after 2.5sec (via SetTimeout) Commented Oct 11, 2021 at 20:30

1 Answer 1

2

I tend to combine *ngIf and async like so:

My component will have an Observable (or in your case a Promise), with a variable name that ends with $. This naming pattern comes from the observable naming guide here

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  //Create a subject with an initial value
  //Keep the subject private so only this component may emit value
  private _mySubject = new BehaviorSubject<any>('initial value!');

  //Expose the observable as a public variable
  //This allows the template to listen for values
  get myObservable$() {
    return this._mySubject.asObservable();
  }

  //helpers for demo!

  emitNull() {
    this._mySubject.next(null);
  }

  emitUndefined() {
    this._mySubject.next(undefined);
  }

  emitNumber(number) {
    this._mySubject.next(number);
  }

  emitText(text) {
    console.log(text);
    this._mySubject.next(text);
  }
}

Then my template:

<div>
  <button (click)="emitNull()">Emit Null</button>
</div>
<div>
  <button (click)="emitUndefined()">Emit Undefined</button>
</div>
<div>
  <button (click)="emitNumber(num.value)">Emit Number</button>
  <input type="number" #num value="42" />
</div>
<div>
  <button (click)="emitText(txt.value)">Emit String</button>
  <input type="text" #txt value="foo" />
</div>

<br />

<h1>Value:</h1>
<ng-container *ngIf="myObservable$ | async as value; else other">
  <div>{{ value }}</div>
  ​ ​</ng-container
>

<ng-template #other>
  <div>The value was null, undefined or empty string</div>
</ng-template>

The template essentially reads as:

if(somevalue) 
    render a div displaying the value
else 
    render a div with text "The value was null..."

The key thing is that async is a pipe. A pipe always transforms some input. In this case, we're passing in an observable (or a promise) and getting some output.

So putting it all together, the template is:

  1. Subscribing to the observable (or then'ing in the case of a promise),
  2. Outputting a something whenever a new value is emitted, capturing it in a variable named value
  3. Performing the if check on value
  4. Conditionally rendering the stuff inside ng-container or using the template marked with #other

Here's a stackblitz demonstrating the above!

As an aside, I recognize my example is using Observable instead of Promises. As I understand it, they essentially work the same. However, I strongly recommend using Observables over Promises in any Angular application. Observables are far more flexible and I think you'll run into far less confusing behavior.

Sign up to request clarification or add additional context in comments.

3 Comments

How does *ngIf behave during the time when the promise is being resolved?
I updated my answer to go into a little more detail.
Thank you, things are clear now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.