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 thee.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.