David
David

Reputation: 87

Javascript - How to use fetch inside a for loop and wait for results

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

Answers (2)

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

Tarun Kumar
Tarun Kumar

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

Related Questions