Reputation: 87
I am new to asynchronous functions, and I am trying to dynamically create an unordered list (ul) containing list items (li) with a child span element in each li. The span contains information coming from a mongo db. I want the for loop to wait for the results in each iteration before continuing. How do I modify this to accommodate the asynchronous operation of fetch?
Thanks in advance.
$('.add').on("input", function() {
var table = document.getElementById("table").getElementsByTagName('tbody')[0];
//Input text
var searchInput = this.value;
var searched_ul = document.getElementById('searched_ul');
fetch("______",{
}).then(response => {
return response.json();
}).then(data => {
for(var i=0; i<data.length; i++){
if(capitalizeFirstLetter(data[i].name).startsWith(capitalizeFirstLetter(searchInput)) && searchInput != ''){
var searched_li = document.createElement('li');
searched_li.innerHTML = data[i].name;
//Outputs all the names from the for loop as expected, but fetch only does last item
console.log("NAME", data[i].name);
//Span child element containing info
var dep_span = document.createElement('span');
//Add css class for styling
dep_span.classList.add('dep-span');
fetch("_______" + data[i].d,{
}).then(response => {
return response.json();
}).then(depData => {
dep_span.innerHTML = depData.name;
//Outputs li and span for last item in for loop (i times)
console.log("LI: ", searched_li);
//Append span to li
searched_li.appendChild(dep_span);
});
searched_li.addEventListener("click", function(e){
});
searched_ul.append(searched_li);
}
}
}).catch(function(err){
console.log(err);
});
});
Upvotes: 2
Views: 3434
Reputation: 311
There are two asynchronous proccess in each fetch, first the http request and then the convertion to json, in this order you can wait for each one of both proceess and save the data in a variable like this:
const fatherData = (await (await fetch("______", {})).json())
Another way with the same results was provided by @TarunKumar he is letting async the fatherRequest but waiting for each one of the childs requests. Just do what better fit your needs.
An example that will wait individually for each response is this:
document.getElementsByClassName('add').addEventListener('keyup', ev => searchData(ev));
const searchData = async (ev) => {
const searchInput = ev.target.value;
const searched_ul = document.getElementById('searched_ul');
const fatherData = (await (await fetch("______", {})).json())
for (const son of fatherData) {
if (capitalizeFirstLetter(son.name).startsWith(capitalizeFirstLetter(searchInput)) && searchInput != '') {
let searched_li = document.createElement('li');
searched_li.innerHTML = son.name;
let dep_span = document.createElement('span');
dep_span.classList.add('dep-span');
let sonData = (await (await fetch("______" + son.d, {})).json())
dep_span.innerHTML = sonData.name;
searched_li.appendChild(dep_span);
searched_li.addEventListener("click", evLi => {
console.log('li clicked')
});
searched_ul.append(searched_li);
}
}
}
Upvotes: 1
Reputation: 44
Possible duplicate of: How to use fetch within a for-loop, wait for results and then console.log it
You need to make the function that starts the loop as async
, then you can use await to wait for fetch completion in the subsequent calls without having to use then
.
In your case, it'll be something like:
fetch("______", {})
.then((response) => {
return response.json();
})
.then(async (data) => {
for (var i = 0; i < data.length; i++) {
//...
const res = await fetch("_______" + data[i].d, {});
const depData = await res.json();
dep_span.innerHTML = depData.name;
//...
}
});
Working example: https://jsfiddle.net/9sdwefyv/34/
Upvotes: 2