1

I have a problem with using fetchs, I have an array of urls that have a JSON content, I want to get the data from all these JSON's and display them in html.

With 1 url I get the result I want:

fetch('myurl1')
.then(response => response.json())
.then(data => {
  let element = document.querySelector('.ele');
  element.innerHTML = `<p>${data.title}</p>`
})
.catch(err => console.log(err))

But when I have several urls I do not know what to do, I want to display the title that it has in all these json files, how do?

Promise.all(urlsArray.map(url =>
  fetch(url)))
  .then(responses => {
    responses.forEach(response => {
      response.json();
      
      let element = document.querySelector('.ele');
      element.innerHTML = `<p>${?????.title}</p>`
    })
  })
  .catch(err => console.log(err))

This is the way I was trying, I do not know how.

PS: .ele is a div

0

3 Answers 3

2

Collect all the results and then render them in whichever HTML form you like e.g.

Promise.all(urls.map(x => fetch(x))
  .then(async responses => {
    const results = await Promise.all(responses.map(x => x.json()));
    const html = results.map(x => `<li>${x.title}</li>`);
    let element = document.querySelector('.ele');
    element.innerHTML = `<ul>${html.join('')}</ul>`;
  })
  .catch(err => console.log(err))

This would result in:

<div class="ele">
  <li>Title A</li>
  <li>Title B</li>
  ...
</div>
5
  • Avoid mixing await with .then(…) syntax
    – Bergi
    Commented Jul 20, 2019 at 10:52
  • @Bergi it won't really impact the code, then returns a Promise regardless. This just allows the code to be more succinct rather than introducing an additional then
    – James
    Commented Jul 20, 2019 at 11:25
  • What about a forEach loop by putting urls in an array?
    – weegee
    Commented Jul 20, 2019 at 18:39
  • @weegee No, forEach is not a good idea. map does it much better.
    – Bergi
    Commented Jul 20, 2019 at 20:40
  • @weegee as Bergi said, forEach with an IO bound call won't guarantee any sort of order, whereas collecting the data first and then processing allows for more control.
    – James
    Commented Jul 22, 2019 at 11:09
0

You can do the same thing as before, using map on the responses to create an array of Promises that resolve to the parsed json data:

Promise.all( urlsArray.map(url =>fetch(url)) )
  .then(responses => {
    return Promise.all(responses.map(response => response.json()))
  })
  .then(dataArray => {
    dataArray.forEach(data => {
      let element = document.querySelector('.ele');
      element.innerHTML = `<p>${data.title}</p>`
    })
  })
  .catch(err => console.log(err))
0

I'd suggest putting all your URLs inside an array and then do a forEach on them one by one and run your methods easily. This won't guarantee an order but will for sure. Don't forget to handle errors

// define our fetch function here just for an example
let fetch = (url) => new Promise(res => setTimeout(() => res(url + " is Fetched"),1000))

let urls = ['url1', 'url2', 'url3'] // all your urls in an array
urls.forEach(url => { // for every url inside the array
  fetch(url) // fetch the url
    .then(data => { // then append them to the document
      var node = document.createElement("LI");
      var textnode = document.createTextNode(data);
      node.appendChild(textnode);
      document.getElementsByTagName("body")[0].appendChild(node)
    })
})

1
  • This does not guarantee any order in which the results are appended to the DOM. Also, you should always handle errors on the end of a promise chain.
    – Bergi
    Commented Jul 20, 2019 at 20:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.