JavaScript Asynchronous Programming with JavaScript Understanding Promises Using Fetch

Junior Aidee
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Junior Aidee
Front End Web Development Techdegree Graduate 14,636 Points

I keep getting an error on the console

const astrosUrl = 'http://api.open-notify.org/astros.json';
const wikiUrl = 'https://en.wikipedia.org/api/rest_v1/page/summary/';
const peopleList = document.getElementById('people');
const btn = document.querySelector('button');

function getProfiles(json) {
  const profiles = json.people.map( person => {
    const craft = person.craft;
    return fetch(wikiUrl + person.name)
      .then( response => response.json() )
      .then( profile => {
        return { ...profile, craft };
      })
      .catch( err => console.log('Error Fetching Wiki: ', err) )
  });
  return Promise.all(profiles);
}

function generateHTML(data) {

  data.map(person => {

    const section = document.createElement('section');
    peopleList.appendChild(section);
    section.innerHTML +=  `
      <img src=${person.thumbnail.source}
      <span>${person.craft}</span>
      <img src=${person.thumbnail ? person.thumbnail.source : null}>
      <h2>${person.title}</h2>
      <p>${person.description}</p>
      <p>${person.extract}</p>
    `;
  });

}


btn.addEventListener('click', (event) => {
  event.target.textContent = "Loading...";
  fetch(astrosUrl)
    .then( response => response.json() )
    .then(getProfiles)
    .then(generateHTML)
    .catch(err => {
      peopleList.innerHTML = '<h3>Something went wrong!</h3>';
      console.log(err)
    })
    .finally( () => event.target.remove() )

});

2 Answers

Cameron Childres
MOD
Cameron Childres
Treehouse Moderator 11,543 Points

Hi Junior,

Take a look at the error in your console:

TypeError: Cannot read property 'source' of undefined
    at callbacks.js:26                 // error originates from line 26
    at Array.map (<anonymous>)         // inside a map method
    at generateHTML (callbacks.js:21)  // inside the generateHTML function

This tells us the nature of the error and where to look for it. On line 26 you have:

<img src=${person.thumbnail.source}

This is the same issue that was causing you trouble on a previous section. Not all of the data returned has a thumbnail property. Additionally your img tag is missing its final angle bracket ">" but this will only cause problems in your HTML.

Two lines later you have a separate img tag that checks if person.thumbnail is valid before accessing the source property:

<img src=${person.thumbnail ? person.thumbnail.source : null}>

While it works for preventing the error, passing null as the source will show a broken image on the page. Passing an empty string instead of null won't show a broken image but will still make an empty img element which gives some odd indentation.

You can use the fix from the previous post which avoids this issue by only producing the img tag if person.thumbnail is defined. You can also solve it with a ternary expression like this:

${person.thumbnail ? `<img src = ${person.thumbnail.source}>` : ""}

I hope this is helpful -- let me know if you have any questions!

Junior Aidee
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Junior Aidee
Front End Web Development Techdegree Graduate 14,636 Points

Thank you Cameron Childres ! I'm still getting the same error about the property 'source' after I made the correction.

const astrosUrl = 'http://api.open-notify.org/astros.json';
const wikiUrl = 'https://en.wikipedia.org/api/rest_v1/page/summary/';
const peopleList = document.getElementById('people');
const btn = document.querySelector('button');

function getProfiles(json) {
  const profiles = json.people.map( person => {
    const craft = person.craft;
    return fetch(wikiUrl + person.name)
      .then( response => response.json() )
      .then( profile => {
        return { ...profile, craft };
      })
      .catch( err => console.log('Error Fetching Wiki: ', err) )
  });
  return Promise.all(profiles);
}

function generateHTML(data) {

  data.map(person => {

    const section = document.createElement('section');
    peopleList.appendChild(section);
    section.innerHTML +=  `
      ${person.thumbnail ? `<img src = ${person.thumbnail.source}>` : ""}
      <img src=${person.thumbnail.source}>
      <span>${person.craft}</span>
      <h2>${person.title}</h2>
      <p>${person.description}</p>
      <p>${person.extract}</p>
    `;
  });

}


btn.addEventListener('click', (event) => {
  event.target.textContent = "Loading...";
  fetch(astrosUrl)
    .then( response => response.json() )
    .then(getProfiles)
    .then(generateHTML)
    .catch(err => {
      peopleList.innerHTML = '<h3>Something went wrong!</h3>';
      console.log(err)
    })
    .finally( () => event.target.remove() )

});
Cameron Childres
Cameron Childres
Treehouse Moderator 11,543 Points

That's because you still have another img tag on the next line.

This line of code says "if person.thumbnail is truthy then return this template of an img tag, otherwise add an empty string":

${person.thumbnail ? `<img src = ${person.thumbnail.source}>` : ""}

The line that you have after it is an img tag, it doesn't check anything, it's just there. If there weren't any errors you would end up with two images.