Inside A Promise I Want To Assign Value(the Value Itself Comes From Some Another Promise ) To A Variable Which Will Be Used Outside Of That Promise
In my Firestore DB, I have two collections books
and categories
. In categories collection all documents have only one field i.e. name
, and in books
collection the document contains multiple field and one of them is type
which is an array of datatype DocumentRef
, which means each document in books can have multiple values of categories-name.
Now, for each document in the books
collection, I want to get all the values of associated categories name in a single string.
This is what I have till now.
database
.collection("books")
.get()
.then(snapshot => {
snapshot.forEach(doc => {
renderTypes(doc);
});
});
/** The renderTypes function **/
renderTypes = doc => {
let typeArrayRef = doc.data().type; // assigning the array of documentRefs
console.log("total elements in types array is ", typeArrayRef.length);
promiseVar = new Promise((resolve, reject) => {
typeList = " ";
// looping through each items inside the array
typeArrayRef.forEach(type => {
type.get().then(res => {
typeList = typeList + " " + res.data().name;
});
// unccommenting this line gives a mixed output (out of order)
// console.log(`String containing all the types are ${ type }`);
});
resolve(type); // resolving with type string
});
promiseVar.then(type => {
console.log("Inside the then of promiseVar", type);
});
};
Now the output I get is :
total elements in types array is 6
total elements in types array is 3
total elements in types array is 1
Inside the then of promiseVar
Inside the then of promiseVar
Inside the then of promiseVar
Nothing is being printed in the last three lines but logging it inside the promiseVar
gives the output but is mixed (i.e. there is no fixed order).
It seems like the promiseVar
is resolving straightaway. Is there any way around this?
Answer
If you want to aggregate a list of async values, you can use Promise.all
and then compute the result. In your case, it may look something like this:
renderTypes = doc => {
const typeArrayRef = doc.data().type; // assigning the array of documentRefs
console.log("total elements in types array is ", typeArrayRef.length);
const promiseVar = Promise
.all(typeArrayRef.map(type => type.get()))
.then(types => {
const typeList = types.map(type => type.data().name).join(' ');
return typeList;
});
promiseVar.then(type => {
console.log("Inside the then of promiseVar", type);
});
};
First, we create a list of promises and wait for all of them to resolve. When it's ready, types
is the list of all responses. Chaining .then
makes promiseVar
resolve the desired result. We can make it even simpler with await
keyword:
renderTypes = async doc => {
const typeArrayRef = doc.data().type; // assigning the array of documentRefs
console.log("total elements in types array is ", typeArrayRef.length);
const types = await Promise.all(typeArrayRef.map(type => type.get()));
const typeList = types.map(type => type.data().name).join(' ');
// Not really _inside_ now.
console.log("Inside the then of promiseVar", typeList);
};
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM