CodeChanger
CodeChanger

Reputation: 8341

Observable not working with async await function in Doc reader

I am trying to put await on Observable like below:

    documentXFDFRetriever: async () => {
            const rows = await this.annotationsService.getAnnotations(this.userService.getCurrentDocumentId()).toPromise();
            console.log(rows);
            return rows.map(row => row.annotationNode);
          }

My Service function:

    public getAnnotations(docId): Observable<Annotation[]> {
        const userId = this.userService.getCurrentUserId();
        const annotationsRef = collection(this.firestore, `annotations/${docId}/${userId}`);
        return collectionData(annotationsRef) as Observable<Annotation[]>;
    }

But it can't return rows on documentXFDFRetriever function.

I m sure something is missing here on the return observable.

Can anyone help me with this issue?

Upvotes: 0

Views: 542

Answers (2)

Mrk Sef
Mrk Sef

Reputation: 8022

Ironically, this exact confusion is why RxJS has deprecated toPromise. If you're using a newer version of RxJS, I would recommend firstValueFrom or lastValueFrom.

If you're using an older version of RxJS, you can use take(1) or first() to ensure the observable completes and resolves the promise.

documentXFDFRetriever: () => this.annotationsService.getAnnotations(
  this.userService.getCurrentDocumentId()
).pipe(
  map(rows => rows.map(row => row.annotationNode)),
  first() // Complete Observable after first emission
).toPromise();

Upvotes: 0

Amer
Amer

Reputation: 6706

That's because the observable toPromise helper function waits for the observable to complete (or error) before actually resolving itself.

So to resolve this issue you can take the first emitted value from the Observable to complete it, before calling the toPromise function, like the following:

// import { take } from 'rxjs/operators';

// by using `take` operator, the converted observable will be completed after emitting one value, then being converted to `Promise`.
const rows = await this.annotationsService.getAnnotations(this.userService.getCurrentDocumentId()).pipe(take(1)).toPromise();

OR if you are using RxJS 7, you can use the firstValueFrom helper function instead of toPormise one, to achieve the same thing.

For more information: https://rxjs.dev/deprecations/to-promise

Upvotes: 2

Related Questions