Build a Pokémon Search App Project - Build a Pokémon Search App

The button doesn’t function. I get “Uncaught TypeError: Cannot read properties of null (reading ‘addEventListener’)” and the type of the form is ‘object’. The code runs perfectly in Visual Studio Code with live server… Any ideas?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pokemon Search App</title>
  <link href="./styles.css" rel="stylesheet" />
  <script src="./script.js" defer></script> 
</head>

<body>
  <h1>Pokemon Search App</h1>
  <div id="application-body">
    <div id="header-div">
      <div>Search for a pokemon name or id:</div>
      <form id="search-form">
        <input id="search-input" />
        <button id="search-button">Search</button>
      </form>
    </div>
    <div id="main-screen-div">
      <div id="info">
        <div id="identity">
          <div id="pokemon-name"></div>
          <div id="pokemon-id"></div>
        </div>
        <div id="size">
          <div id="weight"></div>
          <div id="height"></div>
        </div>
      </div>  
      <div id="sprite-container"></div>
      <div id="types"></div>
    </div>

    <div id="statline">
      <div id="stats-label">Base Stats</div>
      <div class="stats-div">
        <div class="label">HP:</div>
        <div class="stat" id="hp"></div>
      </div>
      <div class="stats-div">
        <div class="label">Attack:</div>
        <div class="stat" id="attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Defence:</div>
        <div class="stat" id="defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Attack:</div>
        <div class="stat" id="special-attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Defence:</div>
        <div class="stat" id="special-defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Speed:</div>
        <div class="stat" id="speed"></div>
      </div>  
    </div>
  </div>
</body>
</html>
const pokemonID = document.getElementById('pokemon-id');
const pokemonName = document.getElementById('pokemon-name');
const spriteContainer = document.getElementById('sprite-container');
const types = document.getElementById('types');
const height = document.getElementById('height');
const weight = document.getElementById('weight');
const hp = document.getElementById('hp');
const attack = document.getElementById('attack');
const defense = document.getElementById('defense');
const specialAttack = document.getElementById('special-attack');
const specialDefense = document.getElementById('special-defense');
const speed = document.getElementById('speed');
const searchForm = document.getElementById('search-form');
const searchInput = document.getElementById('search-input');
const searchButton = document.getElementById('search-button');

const getPokemon = async () => {
  try {
    const pokemonNameOrId = searchInput.value.toLowerCase();

    const response = await fetch(
      `https://pokeapi-proxy.freecodecamp.rocks/api/pokemon/${pokemonNameOrId}`
    );

    const data = await response.json();

    if (!response.ok) {
      pokemonNotFound();
      return;
    }

    updatePokemonData(data);
  } catch (err) {
    console.error('An error occurred:', err);
    alert('An error occurred. Please try again later.');
  }
};

const pokemonNotFound = () => {
  resetDisplay();
  alert('Pokemon not found');
};

const updatePokemonData = (data) => {
  pokemonName.textContent = `${data.name.toUpperCase()}`;
  pokemonID.textContent = `#${data.id}`;
  weight.textContent = `Weight: ${data.weight}`;
  height.textContent = `Height: ${data.height}`;
  spriteContainer.innerHTML = `
    <img id="sprite" src="${data.sprites.front_default}" alt="${data.name} front default sprite">`;
  hp.textContent = data.stats[0].base_stat;
  attack.textContent = data.stats[1].base_stat;
  defense.textContent = data.stats[2].base_stat;
  specialAttack.textContent = data.stats[3].base_stat;
  specialDefense.textContent = data.stats[4].base_stat;
  speed.textContent = data.stats[5].base_stat;
  types.innerHTML = data.types
    .map((obj) => `<span class="type ${obj.type.name}">${obj.type.name}</span>`)
    .join('');
};

const resetDisplay = () => {
  const sprite = document.getElementById('sprite');
  if (sprite) {
    sprite.remove()
  };

  pokemonName.textContent = '';
  pokemonID.textContent = '';
  types.innerHTML = '';
  height.textContent = '';
  weight.textContent = '';
  hp.textContent = '';
  attack.textContent = '';
  defense.textContent = '';
  specialAttack.textContent = '';
  specialDefense.textContent = '';
  speed.textContent = '';
};

searchForm.addEventListener('submit', (e) => {
  e.preventDefault();
  getPokemon();
});

I’ve edited your code for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

1 Like

I think this might be the issue? The JS is loading (I think) before the document, so your element isn’t there yet.

Thank you, sorry, newbie here!!

Already tested with script with or without defer, in the head and in the end of the body… can something else be done?

Hmm, it works fine for me when I put the script tag after the body

Already tried it, no difference. Also called form with
querySelector or
document.forms,
used:
window.addEventListener(‘load’, function() {});

for the entire js,
put js directly in the html in script tag,
deleted form and put listener at the button directly,
used ‘DOMContentLoaded’ at the eventListener… everything works in visual studio code, nothing here…

What is your updated HTML with the script tag where I said?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pokemon Search App</title>
  <link href="./styles.css" rel="stylesheet" />
</head>

<body>
  <h1>Pokemon Search App</h1>
  <div id="application-body">
    <div id="header-div">
      <div>Search for a pokemon name or id:</div>
      <form id="search-form">
        <input id="search-input" required/>
        <button id="search-button">Search</button>
      </form>
    </div>
    <div id="main-screen-div">
      <div id="info">
        <div id="identity">
          <div id="pokemon-name"></div>
          <div id="pokemon-id"></div>
        </div>
        <div id="size">
          <div id="weight"></div>
          <div id="height"></div>
        </div>
      </div>  
      <div id="sprite-container"></div>
      <div id="types"></div>
    </div>

    <div id="statline">
      <div id="stats-label">Base Stats</div>
      <div class="stats-div">
        <div class="label">HP:</div>
        <div class="stat" id="hp"></div>
      </div>
      <div class="stats-div">
        <div class="label">Attack:</div>
        <div class="stat" id="attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Defense:</div>
        <div class="stat" id="defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Attack:</div>
        <div class="stat" id="special-attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Defense:</div>
        <div class="stat" id="special-defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Speed:</div>
        <div class="stat" id="speed"></div>
      </div>  
    </div>
  </div>
  <script src="./script.js"></script> 
</body>
</html>

That’s still inside of the body, put it after the body

I also tried this. Now I have error: An error occurred: [TypeError: Cannot read properties of undefined (reading ‘toUpperCase’)] in the console, and every movement I do I get alert from freeCodeCamp saying: an error occured, please try again later. Code doesn’t work at all, button is dead. All of these versions run perfectly in visual studio code / live server.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Pokemon Search App</title>
  <link href="./styles.css" rel="stylesheet" /> 
</head>

<body>
  <h1>Pokemon Search App</h1>
  <div id="application-body">
    <div id="header-div">
      <div>Search for a pokemon name or id:</div>
      <form id="search-form">
        <input id="search-input" required />
        <button id="search-button">Search</button>
      </form>
    </div>
    <div id="main-screen-div">
      <div id="info">
        <div id="identity">
          <div id="pokemon-name"></div>
          <div id="pokemon-id"></div>
        </div>
        <div id="size">
          <div id="weight"></div>
          <div id="height"></div>
        </div>
      </div>  
      <div id="sprite-container"></div>
      <div id="types"></div>
    </div>

    <div id="statline">
      <div id="stats-label">Base Stats</div>
      <div class="stats-div">
        <div class="label">HP:</div>
        <div class="stat" id="hp"></div>
      </div>
      <div class="stats-div">
        <div class="label">Attack:</div>
        <div class="stat" id="attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Defence:</div>
        <div class="stat" id="defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Attack:</div>
        <div class="stat" id="special-attack"></div>
      </div>
      <div class="stats-div">
        <div class="label">Sp. Defence:</div>
        <div class="stat" id="special-defense"></div>
      </div>
      <div class="stats-div">
        <div class="label">Speed:</div>
        <div class="stat" id="speed"></div>
      </div>  
    </div>
  </div>
</body>
<script src="./script.js"></script>
</html>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.