Reputation: 303
My code for accessing a document from firestore is as below.
let data;
this.firestore.collection('groups').doc(tempId).ref.get().then(function(doc) {
if (doc.exists) {
data = doc.data();
console.log("Document data:", doc.data()); // Gives correct data here
} else {
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
console.log("Service Data :: " + data); //It says undefined here.
Here, I want to return the data of doc.data() to another component. But, In the console.log("Service Data :: " + data); it says undefined.
So, I'm confused like why data variable does not has the value of doc.data() in it.
Upvotes: 0
Views: 885
Reputation: 6016
This might be the reason , where second console statement is executing before first. Thread based execution will make the request to your firestore
and it will not wait for the response where as it will executes other lines of code. So your second console is executing before the first.
let data;
this.firestore.collection('groups').doc(tempId).ref.get().then(function(doc) {
if (doc.exists) {
data = doc.data();
console.log("Document data:", doc.data()); // first console
} else {
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
console.log("Service Data :: " + data); //second console
If you want to change this behavior try call your second console next to the first one.
If you want pass the data to other component use BehaviourSubject
public dataSource = new BehaviorSubject<any>([]);
this.dataSource.next(doc.data());
console.log("Document data:", doc.data()); // first console
Try to pass dataSource
object to your other component with help of service class. follow this link for more info about angular-behaviorsubject-service
second Component.ts
constructor(private service: Commonservice) { }
someMethod() {
this.service.dataSource.subscribe((response: any) =>{
// do something with data
})
}
Upvotes: 2
Reputation: 1687
the .get()
method returns a promise, which is executed asynchronously once you call .then()
. Because of this, the next line that gets executed is
console.log("Service Data :: " + data);
. Javascript does not wait for the promise to be resolved and instead just carries on with the next synchronous line which is the second console.
The way I usually go about this is passing the whole promise to the other component or better yet, I use the .valueChanges()
of the .doc()
which returns an observable, and use the async pipe in the component I'm passing to:
// Get Observable on document. Returns Observable<any>
const group$ = this.firestore.doc('/groups' + tempId).valueChanges();
You then have two options:
group$.subscribe();
group$
to the component you want and use the async pipe thereFirst option:
// In your component:
let data;
group$.subscribe(doc => {
if (doc.exists) {
data = doc
console.log("Document data:", doc); // No need to call data().
} else {
console.log("No such document!");
},
error => console.log("Error getting document:", error);
)
Second option, passing into the component where you would like the observable to be evaluated and the data displayed:
<div *ngIf="group$ | async as doc">
Your html here {{ doc.someProperty }} further html here...
</div>
Personally, I prefer the second choice because it goes along with the framework nicely and keeps me from making asynchronous errors.
Have a look at angularfire2's Github repo for docs here. If there is no need to evaluate the observable by hand in code, I would not do this and let the framework handle it.
One final thing: If you use the observable and want to do some error handling when using the async pipe, you probably want to do so when creating the observable:
// Get Observable on document. Returns Observable<any>
// In error case, returns Observable of the error string
const group$ = this.firestore.doc('/groups' + tempId).valueChanges()
.pipe(
catchError(error => of(`Error getting document: ${error}`))
);
Upvotes: 1