Vern Halen
Vern Halen

Reputation: 63

Angular Async Pipe and the 'delay' operator

I'm attempting to simulate latency with my observables.

I want to unwrap the observable using the async pipe, and add a bit of delay with the 'delay' operator.

app.component.html

<ul *ngIf="items$ | async as items">
   <li *ngFor=let item of items">{{ item }}<li>
</ul>

app.component.ts

get items$(): Observable<string[]> {
    return of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}

However, doing it in this fashion returns no HTML markup. Removing the pipe(delay(3000)) allows it to work.

If I implement 'OnInit' and just check on the observable:

ngOnInit(): void {
   this.items$.subscribe(val => console.log(val));
}

In three seconds the console will output:

(4) ["alpha", "bravo", "charlie", "delta"]

So the observable is behaving like I want it to, but it seems I am not utilizing the async pipe correctly.

What am I missing about about how the async pipe works? How do I simulate this delay in a simple fashion?

Upvotes: 2

Views: 2813

Answers (1)

Igor
Igor

Reputation: 62213

You need a single Observable instance. Your code currently will create and return a new Observable every time your property items$ is accessed. Create it one time instead. You could still use a getter if you wanted to as long as it is the same Observable instance being returned with each call.

items$: Observable<string[]>;
constructor() {
  this.items$ =  of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}

or

private _items$?: Observable<string[]>;
get items$(): Observable<string[]> {
  if (!this._items$) {
    this._items$ =  of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
  }
  return this._items$;
}

If you want to see how/why your original code is failing you could add a counter in the getter and then you can see the number of Observable being created and returned.

  numberOfCalls = 0;
  get items$(): Observable<string[]> {
    this.numberOfCalls++;
    return of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
  }

and then add this to your template

calls to items$ which create and return a new observable = {{numberOfCalls}}

Upvotes: 4

Related Questions