1👍
The problem is that the Firestore query is asynchronous but you aren’t waiting for the response before continuing. Effectively what you have is this:
getDefaultAnswer () {
var data
// This next bit is asynchronous
db.doLotsOfStuff().then(querySnapshot => {
// This callback won't have been called by the time the outer function returns
querySnapshot.forEach(doc => {
data = doc.data()
})
})
return data
},
The asynchronous call to Firestore will proceed in the background. Meanwhile the rest of the code in getDefaultAnswer
will continue to run synchronously.
So at the point the code reaches return data
none of the code inside the then
callback will have run. You can confirm that by putting in some console logging so you can see what order the code runs in.
The use of then
to work with asynchronous code is a feature of Promises. If you aren’t already familiar with Promises then you should study them in detail before going any further. Here is one of the many guides available:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
The bottom line is that you cannot force the getDefaultAnswer
method to wait for the asynchronous action to complete. What you can do instead is to return a suitable Promise and then wait for that Promise to resolve before you call onNotSelectedAnswer
. It might look something like this:
getDefaultAnswer () {
// We return the Promise chain from getDefaultAnswer
return db.doLotsOfStuff().then(querySnapshot => {
var data = null
// I have assumed that forEach is synchronous
querySnapshot.forEach(doc => {
data = doc.data()
})
// This resolves the Promise to the value of data
return data
})
},
It is important to appreciate that the method getDefaultAnswer
is not attempting to return the value of the data. It is instead returning a Promise that will resolve
to the value of the data.
Within CountTerminated
you would then use it like this:
this.getDefaultAnswer().then(defaultAnswer => {
this.onNotSelectedAnswer(defaultAnswer)
})
or if you prefer:
this.getDefaultAnswer().then(this.onNotSelectedAnswer)
The latter is more concise but not necessarily clearer.
You could also write it using async
/await
but I wouldn’t advise trying to use async
/await
until you have a solid grasp of how Promises work. While async
/await
can be very useful for tidying up code it is just a thin wrapper around Promises and you need to understand the Promises to debug any problems.
The code I’ve suggested above should work but there is a delay while it waits for the asynchronous request to complete. In that delay things can happen, such as the user may click on a button. That could get you into further problems.
An alternative would be to load the default answer much sooner. Don’t wait until you actually need it. Perhaps load it as soon as the question is shown instead. Save the result somewhere accessible, maybe in a suitable data
property, so that it is available as soon as you need it.