Why is RxJS pipe in ngOnInit not executed when the Observable is initialised at class level?

630 Views Asked by At

When the Observable is initialised at the class property declaration level, why does the pipe in ngOnInit is not being fired when the async pipe unwraps the Observable?

I know I can do the initialisation in ngOnInit itself but I am just trying to get a better understanding of how RxJS streams work. I am also aware I can call subscribe() in ngOnInit but that is not my intention.

I have tried doing things like adding a fake loading to "delay" the template rendering in hopes to delay the async pipe but it is still not working.

Component:

export class MyComponent implements OnInit {

  constructor(
    private dataService: DataService
  ) { }

  items$: Observable<Item[]> = this.dataService.getItems();

  ngOnInit(): void {
    this.items$.pipe(
      tap(data => {
        console.log('items', data);     // <--- this doesn't get called
      })
    )
  }

}

Template:

<div *ngFor="let item of items$ | async">{{ item.name }}</div>
1

There are 1 best solutions below

0
Joosep Parts On

While there are good comments on how to fix it, I'll explain why it is so.

tap (or do in the old version of RxJS) -> Transparently perform actions or side-effects, such as logging (as definition already says).

In your case, you don't .subscribe() to your Observable, and that's why you don't see your "Item" logged in the console. You got some options.

  1. Option to subscribe in the template using | async pipe.
  2. Or using .subsribe() in your component.

Using async pipe

You could also tap directly on the observable and do not need to subscribe/unsubscribe, because that's handled by | async pipe.

<div *ngIf="items$ | async"></div>
  items$: Observable<Item[]> = this.dataService.getItems().pipe(
    tap((data) => {
      console.log('items', data);
    })
  );

  ngOnInit(): void {}

Using .subscribe()

If you add .subscribe() your going to start getting console logs. Though then you also need to unsubscribe after your done.

    this.items$.pipe(
      tap(data => {
        console.log('items', data);
      })
    ).subscribe();

Working example: https://stackblitz.com/edit/angular-ivy-fcp9fz?file=src%2Fapp%2Fapp.component.ts