1

In my Angular service I am providing a public Observable called usageDoc$.

service.ts:

usageDoc$: Observable<IUsage>;

initializeUsageDoc() {
  //gets called in app.component.ts on app load
  ...
  //some async db querying

  this.usageDoc$ = this.firestore.getUsageDoc(user.uid);  //getUsageDoc(..) returns Observable<IUsage>
}

component.ts

localDoc: any;

ngOnInit() {
  this.service.usageDoc$.subscribe(doc=>this.localDoc=doc);
}

This leads to the following error: cannot read property subscribe of undefined... as usageDoc$ is not yet set on the component init. Currently I am using a workaround by creating a second observable usageDocReady$ = new Subject<boolean> in service that emits as soon as usageDoc$ is set.

Is there better to solve this issue? Can I somehow initialize usageDoc$ with a default value?

I know I would not have this issue if I'd subscribe in template using the async pipe, but I need a normal variable for displaying matters, hence the use of localDoc.

Tobias Kaufmann
  • 625
  • 1
  • 5
  • 19

1 Answers1

2

I'd suggest using a ReplaySubject with buffer 1. It'd ensure future subscribers would get the last emission whilst avoiding any undefined errors.

private usageDocSrc = new ReplaySubject<IUsage>(1);
public usageDoc$ = this.usageDocSrc.asObservable();

initializeUsageDoc() {
  //gets called in app.component.ts on app load
  ...
  //some async db querying

  this.firestore.getUsageDoc(user.uid).subscribe({
    next: value => this.usageDocSrc.next(value)
  });
}

If you don't wish to use a ReplaySubject, then I don't understand the need for the Observable. You could directly return the observable from getUsageDoc() function.

initializeUsageDoc(): Observable<IUsage> {
  //gets called in app.component.ts on app load
  ...
  //some async db querying

  return this.firestore.getUsageDoc(user.uid);
}

Although this would invoke all the statements prior to getUsageDoc() for each subscription to initializeUsageDoc().

ruth
  • 29,535
  • 4
  • 30
  • 57
  • What's the point of having `usageDoc$` and `usageDocSrc`? – Bojan Kogoj Mar 04 '21 at 13:20
  • @BojanKogoj: It's a force of habit using the [`asObservable()`](https://stackoverflow.com/a/36989035/6513921) construct from a multicast like `Subject` or `ReplaySubject`. Some would prefer not using it: `usageDoc$ = new ReplaySubject(1)`. See also [here](https://stackoverflow.com/a/59103116/6513921). – ruth Mar 04 '21 at 13:23
  • Ok makes sense if you are trying to prevent anyone from nexting from outside service. In this case make `usageDocSrc` private as well? – Bojan Kogoj Mar 04 '21 at 13:26
  • @BojanKogoj: Yes that is the convention (or at least it used to be). I've updated the answer. – ruth Mar 04 '21 at 13:28