Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript Asynchronous Programming with JavaScript Asynchronous JavaScript with Callbacks Implement a Callback

How to solve the problem of some astronauts' names leading to disambiguation pages on Wikipedia

I have discovered two things can go wrong with this application, depending on who is in outer space and what kind of wikipedia page that person has.

1: When we're building a URL using the name of an astronaut, that URL can some times lead to a disambiguation page, instead of the page of the astronaut.

2: The person's page lacks a photograph

In both cases, the result is an empty box being rendered on the page.

I solved problem number 2 by adding an additional condition to the if statement in generateHTML, like this:

The original:

if (data.type === 'standard')

My changed version:

if (data.type === 'standard' && data.thumbnail != undefined)

This makes it so that if there is no photograph, then the else block is entered, which creates a box with a placeholder image, and things work out. I even get some wikipedia information in the box.

However, I could not solve problem number 1. Astronauts whose names lead to disambiguation pages also caused an undefined data.thumbnail, just like astronauts whose pages lacked photographs. I was working on the problem, but then the astronaut who was in outer space who caused this issue returned to Earth, and with no astronaut whose name lead to a disambiguation page, I could not test my solutions.

It's worth mentioning that I did not try my solution to problem number 2, on problem number 1. That astronaut left space before I did that, so I don't know whether it would have worked, but I suspect that it wouldn't have.

What solutions do you think that I could have gone for? If this problem returns in the future, and you solve it, please tell me how you did it here. I'll be even more grateful if you can solve both problems.

I'm pretty sure that part of the solution is to 1: Detect that we are on a disambiguation page 2: Change the URL that we send a request to, by adding (cosmonaut), _(astronaut), or _(taikonaut) to the end. For example, this disambiguation page: https://en.wikipedia.org/wiki/Sergey_Korsakov would become this cosmonaut page: https://en.wikipedia.org/wiki/Sergey_Korsakov(cosmonaut)

I don't know how to do this. I also don't know how to differentiate between cosmonauts, astronauts, and taikonauts.

Also, my first solution was to simply not render a box for any astronaut who had any sort of issue, but I don't like that "solution" as it removes potential content that should be included.

For reference, here is the original code that the instructor wrote, in callback.js (without my tiny change):

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');

// Make an AJAX request
function getJSON(url, callback) {
  const xhr = new XMLHttpRequest();
  xhr.onreadystatechange = () => {
    if(xhr.readyState === 4) {
      if (xhr.status === 200) {
        let data = JSON.parse(xhr.responseText);
        callback(data);
      }
    }
  };
  xhr.open('GET', url);
  xhr.send();
}

// Generate the markup for each profile
function generateHTML(data) {
  btn.style.display = "none";
  const section = document.createElement('section');
  peopleList.appendChild(section);

  // Check if request returns a 'standard' page from Wiki
  if (data.type === 'standard') {
    section.innerHTML = `
      <img src=${data.thumbnail.source}>
      <h2>${data.title}</h2>
      <p>${data.description}</p>
      <p>${data.extract}</p>
    `;
  } else {
    section.innerHTML = `
      <img src="img/profile.jpg" alt="ocean clouds seen from space">
      <h2>${data.title}</h2>
      <p>Results unavailable for ${data.title}</p>
      ${data.extract_html}
    `;
  }
}


btn.addEventListener("click", () => 
{
 getJSON(astrosUrl, (json) => 
 {
   json.people.map(person => 
   {
     getJSON(wikiUrl + person.name, generateHTML);
   });
 });
});

1 Answer

Jean-Luc Leigh
Jean-Luc Leigh
8,486 Points

Well I solved it by altering the generateHTML function like so:

function generateHTML(data) {
  //if-block I added
  if(data.type === 'disambiguation') {
      const pattern = /[A-Z][a-z]*\s[A-Z][a-z]*\s(\(astronaut\)|\(cosmonaut\)|\(taikonaut\))/;
      const spacedata = data.extract.match(pattern)[0];
      getJSON(wikiUrl + spacedata, generateHTML);
      // Check if request returns a 'standard' page from Wiki
  } else if (data.type === 'standard') {
  const section = document.createElement('section');
  peopleList.appendChild(section);
    section.innerHTML = `
      <img src=${data.thumbnail.source}>
      <h2>${data.title}</h2>
      <p>${data.description}</p>
      <p>${data.extract}</p>
    `;
  } else {
    section.innerHTML = `
      <img src="img/profile.jpg" alt="ocean clouds seen from space">
      <h2>${data.title}</h2>
      <p>Results unavailable for ${data.title}</p>
      ${data.extract_html}
    `;
  }
}

First I check if the type of page i've got is a "disambiguation" page. Then, since the extract containing the different possibilities is just one long string, I use a regular expression to find the entry I'm looking for. The regular expression here looks for two capitalised words (the assumption being that the person only has a name and surname) followed by one of the following strings: "(astronaut)", "(cosmonaut)" or "(taikonaut)". The .match() method with the regurlar expression I used returns an array from which I only need the first entry, which is then used in the getJSON() function. The if-statement:

if (data.type === 'standard')

had to be moved to in front of:

  const section = document.createElement('section');

also to prevent the creation of a bunch of empty sections.