Friso Hoekstra
Friso Hoekstra

Reputation: 885

Return observable from async function

TLDR; I have a Promise collection().add() which resolves to an object DocumentReference with a listener function onSnapshot() that emits data.

I need to return an Observable which, upon subscription, calls the Promise, subscribes to the listener function on the resolved object, and broadcasts the values from the listener to subscriber.next()

Context: I am trying to declare a function that creates a Firestore document, then returns an Observable with the document data, using the onSnapshot() function on its DocumentReference returned by collection().add().

Based on: https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/f6972433dea48bf1d342a6e4ef7f955dff341837/demo-ng/app/item/items.component.ts#L175-L185

async create(project) {
    const ref = await this.db.collection('projects').add(project);
    return new Observable(subscriber => {
        ref.onSnapshot(doc => {
            // ...
            subscriber.next(doc.data());
        });
    });
}

Current behaviour:async/await always returns a Promise, I need the function to return an observable.

Expected: I need a slice of data from the ref.onSnapshot() callback, in this case doc.data(), to use it in my template, e.g.

// ... 

this.service.create(project).subscribe(project => console.log(project));

Upvotes: 9

Views: 9508

Answers (1)

B M
B M

Reputation: 4019

In your implementation create returns a promise, since as you pointed out it needs to work async. If this is a fact then you have to modify the context calling create: simply make the calling function async as well and add await before the call to create: await create(...).

As an alternative, if you want to return an observable no matter what, you have to stop awaiting the db.collection().add() and remove the async before create. Then you can return the observable directly and inside the .then function of db.collection().add() you could update the observable with doc.data():

create(project) {
    return new Observable(subscriber => {
        this.db.collection('projects').add(project)
           .then(ref => {
                ref.onSnapshot(doc => {
                    // ...
                    subscriber.next(doc.data());
                });
           });
    });
}

Note that await is just one way to handle a Promise. The more classical way is attaching a callback to its .then. Note that .then again returns a Promise which again has a .then and so on - this is how Promises are defined.

Upvotes: 12

Related Questions