Search code examples
angularrxjsreactive-programming

Why does the async pipe not subscribe to observable inialized in the constructor


See this plunkr for an illustration: https://plnkr.co/edit/Tm4AW0sU0pumBA8I?open=lib%2Fapp.ts&deferRun=1

Component 1 where i declare everything in the class initializer:

@Component({
  template: '{{ data$ | async | json }}',
  selector: 'app-data'
})
export class AppData {
  readonly id$ = new Subject();
  readonly data$ = this.id$.pipe(
    switchMap(id => of(`id = ${id}`))
  );

  @Input()
  set id(val: number) {
    this.id$.next(val)
  }
}

And Component 2 where I create the observable onInit:

@Component({
  template: '{{ data$ | async | json }}',
  selector: 'app-data-oninit'
})
export class AppDataOnInit implements OnInit {

  @Input()
  id: number;

  data$: any;


  ngOnInit(): void {
    this.data$ = of(`id = ${this.id}`)
  }
}

I am trying to declare the observable in the component contructor or class initialzier but the async pipe is not subscribing to it there. However if I instanciate the observable in ngOnInit it works as expected.

I have been searching all day for an explanation for this but come up empty. What is the missing puzzle piece here?

I feel like it makes more sense to declare the observables when the class is created.


Solution

  • The async pipe is subscribing to your data$, but this subscription is happening after id$ has emitted. If you want late subscribers to receive prior emisssions, you can use a ReplaySubject instead of a plain Subject:

    readonly id$ = new ReplaySubject(1);