How to Build a Star Wars Character Dropdown with JavaScript

In this tutorial, we'll learn how to build a character selector using the Star Wars API (SWAPI). We'll use modern JavaScript and the Fetch API to retrieve data and dynamically update the UI.

5 min read JavaScript,ES6
JavaScript,ES6

How to Build a Star Wars Character Dropdown with JavaScript

In this tutorial, we'll learn how to build a character selector using the Star Wars API (SWAPI). We'll use modern JavaScript and the Fetch API to retrieve data and dynamically update the UI.

Let's get started

First, let's talk about what we'll be building. The character selector will consist of a dropdown list of characters, and when a user selects a character, the app will display their details. We'll also include error handling for when the API calls fail.

To get started, we'll need to add an event listener for when the DOM is loaded. This will ensure that our JavaScript code only runs when the page is fully loaded. We'll also define our API base URL.

document.addEventListener("DOMContentLoaded", () => {
  const apiBaseUrl = "https://swapi.dev/api/";

  // Code for character selector goes here
});

Next, we'll create our character dropdown list. We'll use the createElement method to create a select element, add a class of form-control to it, and append it to the document.body. We'll also create a div element that we'll use to display the character details.

const characterDropdown = document.createElement("select");
characterDropdown.classList.add("form-control");
document.body.appendChild(characterDropdown);

const characterDetailsWrap = document.createElement("div");

Now, we'll define a function that will retrieve the list of characters from the API and populate our dropdown list. We'll use async/await to make our API call, and we'll handle any errors that occur.

const setCharacters = async () => {
  try {
    const response = await fetch(`${apiBaseUrl}people/`);
    const { results } = await response.json();

    characterDropdown.innerHTML = `<option value="">Select a character</option>`;
    results.forEach(({ name }, index) => {
      characterDropdown.innerHTML += `<option value="${index + 1}">${name}</option>`;
    });
  } catch (error) {
     characterDropdown.add(new Option('Error, no characters found', ''))
    console.error(`Error fetching characters: ${error.message}`);
  }
};

Our next function will retrieve the details for a selected character and display them in the UI. We'll again use async/await to make our API calls, and we'll handle any errors that occur. We'll also format the character details into an HTML list and append it to our characterDetailsWrap div.

const getPlanet = async (id) => {
    const response = await fetch(`${apiBaseUrl}planets/${id}`);
    const data = await response.json();
    return data;
  };

  const setDetails = async (id) => {
    try {
      // fetch details & store object
      const response = await fetch(`${apiBaseUrl}people/${id}`);
      const data = await response.json();
      // destruct what we want
      const {
        name,
        height,
        mass,
        hair_color,
        skin_color,
        eye_color,
        birth_year,
        gender,
        homeworld
      } = data;
      const planetResponse = await fetch(homeworld);
      const planetData = await planetResponse.json();
      const planet = {
        name: planetData.name,
        population: planetData.residents.length
      };
      // build UI
      characterDetailsWrap.innerHTML = `<ul class="list-group list-group-flush">
            <li class="list-group-item"><b>Full Name</b>: ${name}</li>
            <li class="list-group-item"><b>Height</b>: ${height}</li>
            <li class="list-group-item"><b>Mass</b>: ${mass}</li>
            <li class="list-group-item"><b>Hair Color</b>: ${hair_color}</li>
            <li class="list-group-item"><b>Skin Color</b>: ${skin_color}</li>
            <li class="list-group-item"><b>Eye Color</b>: ${eye_color}</li>
            <li class="list-group-item"><b>Birth Year</b>: ${birth_year}</li>
            <li class="list-group-item"><b>Gender</b>: ${gender}</li>
            <li class="list-group-item"><b>Home World</b>: ${planet.name} - Population ${planet.population}</li></ul>`;
      // display UI
      characterDropdown.after(characterDetailsWrap);
    } catch (error) {
      console.error(`Error fetching character details: ${error.message}`);
    }
  };

The code above shows an example of how to use the Star Wars API to create a character selector that displays character details and their homeworld's population.

characterDropdown.addEventListener("change", (e) => {
    const id = e.target.value;
    characterDetailsWrap.innerText = "";
    setDetails(id ? id : "");
  });

  setCharacters();

The code above adds an event listener to the character dropdown menu that listens for a "change" event. When a user selects a character from the dropdown, the event is triggered, and the callback function is executed.

The callback function retrieves the value of the selected character ID from the event object using e.target.value and assigns it to a variable id. It then sets the inner text of the character details wrap element to an empty string using characterDetailsWrap.innerText = "".

Finally, it calls the setDetails function with the id parameter, which displays the details of the selected character in the characterDetailsWrap element.

The last line of the code block calls the setCharacters function, which initializes the dropdown menu with a list of characters fetched from the Star Wars API.

In conclusion

This code can be a great starting point for a UX engineer who wants to create a simple interface for users to interact with. It shows how to use async/await to fetch data from an API and dynamically update the UI with the results.

One thing to keep in mind is that this code does not include any styling. As a UX engineer, you'll need to use your design skills to create a visually appealing and intuitive interface that users will enjoy using.

You could consider adding animations to make the UI more engaging, or using colors and typography to highlight important information. Additionally, you could add error handling to make sure that users are informed if there are any issues with fetching data from the API.

Overall, this code is a great example of how a UX engineer can work with developers to create an interface that is both functional and visually appealing. By understanding how to use async/await and fetch data from APIs, UX engineers can create interfaces that make it easy for users to find the information they need.

You can find a working example here: View CodePen