1

I am trying to pull some data from this website by referring to their documentation at https://dog.ceo/dog-api/documentation/

I am trying to retrieve the list of dog breeds and create a list. I am using javaScript's "fetch"

let dog_list = [];
fetch('https://dog.ceo/api/breeds/list/all')
  .then(response => {
    if (response.ok) {
      return response.json();
    } else {
      throw new Error(response.statusText);
    }
  })
  .then(data => dog_list = data.message)
const container = document.getElementById("container");
for (dog in dog_list) {
  let li = document.createElement("li");
  let node = document.createTextNode(dog);
  li.appendChild(node);
  container.appendChild(li);
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Dog Breed List</title>
</head>

<body>
  <ul id="container"></ul>
  <script src="dog_breed.js"></script>
</body>

</html>

I am having issues at the second "then" where I have no idea on how to convert the json object into array and display them as

  • dog1
  • dog2
  • dog3
Chai Chong Teh
  • 113
  • 1
  • 7
  • 2
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – adiga Mar 10 '19 at 17:22
  • Move the `for` loop inside the callback. `.then(data => { dog_list = data.message; const container = document.getElementById("container"); for (dog in dog_list) {....} })` – adiga Mar 10 '19 at 17:23
  • Your loop runs before the dogs are fetched.. – Mr. Alien Mar 10 '19 at 17:24

3 Answers3

5

Just construct you li inside the callback where you create dog_list...

Something like this...

let dog_list = [];
const container = document.getElementById("container");
fetch('https://dog.ceo/api/breeds/list/all')
    .then(response => {
        if (response.ok) {
            return response.json();
        } else {
            throw new Error(response.statusText);
        }
    })
    .then(data => {
        dog_list = data.message;
        for (dog in dog_list) {
            let li = document.createElement("li");
            let node = document.createTextNode(dog);
            li.appendChild(node);
            container.appendChild(li);
        }
    });

Why do you need to construct resulting DOM structure inside promise handler?

Because the complete fetch(/*...*/).then(/*...*/).then(/*...*) block will be executed asynchronously

Without waiting for that code to complete, mainline ('global') code will continue its execution from the line after that, which in your case is getting the container and start adding li elements. Problem is that at this point the processing of the response from the fetch call will not even start (even if the fetch has been executed and results have been returned) and consequently dog_list will be empty.

Community
  • 1
  • 1
Milan
  • 1,903
  • 17
  • 16
2

Since the callback in .then is asynchronous, you can populate the list inside the .then callback otherwise dog_list will still be an empty array the time when the loop runs:

fetch('https://dog.ceo/api/breeds/list/all')
  .then(response => {
    if (response.ok) {
      return response.json();
    } else {
      throw new Error(response.statusText);
    }
  })
  .then(data => populate(data.message));
function populate(dog_list){
    const container = document.getElementById("container");
    for (dog in dog_list) {
      let li = document.createElement("li");
      let node = document.createTextNode(dog);
      li.appendChild(node);
      container.appendChild(li);
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Dog Breed List</title>
</head>

<body>
  <ul id="container"></ul>
</body>

</html>
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
1

You could also try the same with async and await. Please have a look below.

const url = 'https://dog.ceo/api/breeds/list/all';

async function Main() {
  const dog_data = await getDogData(url).catch(catchError);
  const dog_list = dog_data.message;
  const container = document.getElementById("container");
  for (dog in dog_list) {
    const node = createHTMLElement('li', dog);
    container.appendChild(node);
  }
}

function catchError(err) {
  console.log('Error ', err);
}

function createHTMLElement(_node, data) {
  let li = document.createElement("li");
  li.textContent = dog;
  return li;
}

async function getDogData(_url) {
  const response = await fetch(_url);
  return await response.json();
}

Main();
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Dog Breed List</title>
</head>

<body>
  <ul id="container"></ul>

</body>

</html>
Kuldeep Bhimte
  • 961
  • 1
  • 10
  • 25
  • 1
    Wow, a clear path on where to read up after this, I am still relatively new in JS, never knew that async and await exist. Thank you for shedding the light. – Chai Chong Teh Mar 10 '19 at 23:29