30 Days Of JavaScript

Day 28: PokeDex Day 3

Lesson 4: PokeDex 12

Finally let's add the ability to compare two Pokemon.

We will add a dropdown to the modal that lists all the other loaded Pokemon. When the user selects a Pokemon from that list we will fetch the stats for it from our Pokemon array and its data to the chart.

We've got quite a few fiddly code changes to make to get this working.

First of all add this block of HTML to your modal, place it directly underneath the line <div id="modal-title">Wartortle</div>.

1<div>
2  <label>Compare with</label>
3  <select id="compare-list"></select>
4</div>

When we load our modal we want to take all the Pokemon in our pokemonArray and add them to that drop down. As we can fetch new pokemon between modal opening, we might not be loading the same list of Pokemon each time. So we need to remove the options first and then add the whole list from scratch again.

We need a reference to the dropdown, so add this near the top:

1const compareList = document.getElementById("compare-list");

Add this to the top of your showModal function:

1while (compareList.firstChild) {
2  compareList.removeChild(compareList.lastChild);
3}
4
5pokemonArray.forEach((p) => {
6  const option = document.createElement("option");
7  option.value = p.id;
8
9  let firstLetter = p.name.charAt(0);
10  firstLetter = firstLetter.toUpperCase();
11  const restOfOption = p.name.substring(1);
12
13  option.innerText = `${firstLetter}${restOfOption}`;
14
15  if (p.id === pokemonId) {
16    option.selected = true;
17  }
18
19  compareList.appendChild(option);
20});

This removes any existing options and then:

  • Creates an HTML option element
  • Sets its value to the id of the Pokemon
  • Capitalizes the first letter of the Pokemon's name
  • Sets its innerText to the name of the Pokemon
  • Sets the currently selected option to the id of Pokemon we've loaded the modal for.
  • Adds the option node to the dropdown

Now when you load the modal you should have a dropdown with all the loaded Pokemon in it.

Next we need to create an event handler to deal with selecting a new Pokemon.

Add these lines to your JavaScript:

1const compare = (e) => {
2  const newPokemonId = e.target.value;
3  const comparisonPokemon = pokemonArray.find((p) => p.id === +newPokemonId);
4
5  const newPokemonStats = comparisonPokemon.stats.map((stat) => stat.base_stat);
6
7  const newDataset = {
8    label: comparisonPokemon.name,
9    data: newPokemonStats,
10    borderWidth: 1,
11  };
12
13  if (currentChart.data.datasets.length === 2) {
14    currentChart.data.datasets[1] = newDataset;
15  } else {
16    currentChart.data.datasets.push(newDataset);
17  }
18
19  currentChart.update();
20};

This compare will be called when the drop down selection changes.

  • It gets the newly selected Pokemon id from the e.target.value.
  • It then finds that Pokemon in the pokemonArray. You may notice something new here: +newPokemonId. This is a sneaky and relatively advanced way of turning a string into a number. If we don't do this, then the === will fail because it is trying to compare a number to a string using exactly equals (===) which will fail. If we used == then it would pass but it's clearer to cast the string to a number before the comparison.
  • Next up we get an array of the new Pokemon's stats.
  • From that we create a dataset.
  • Then we check if there are 2 datasets already displayed, if there are then we simply change the second dataset.
  • If there isn't a second dataset then this must be the first time doing this comparison so we need to add a new dataset rather than change the existing second one.
  • Then we update the chart so it rerenders.

The final thing to fix is to remove the second data set if we select the Pokemon we are currently viewing.

To do that we need to make our foundPokemon globally accessible.

In showModal remove the const in front of foundPokemon = ... and instead declare it as:

1let foundPokemon;

Up with the other global variables near the top, just below let currentChart; would be perfect.

Now, down in compare, change our if/else check to this:

1if (foundPokemon.id === +newPokemonId && currentChart.data.datasets.length) {
2  currentChart.data.datasets.pop();
3} else if (currentChart.data.datasets.length === 2) {
4  currentChart.data.datasets[1] = newDataset;
5} else {
6  currentChart.data.datasets.push(newDataset);
7}

Here we add an initial check to see if we are trying to view the currently viewed pokemon and if there is already a second dataset in the chart. If there is then .pop() the last element off the array.

Outline

Go Pro?

If you upgraded to pro, sign in here

  • About
  • Blog
  • Privacy
Looking to email me? You can get me on my first name at allthecode.co