skip to Main Content

I am working on creating a weather app however, it is showing me this error: "Cannot read properties of null (reading ‘addEventListener’)".Below is the javascript code.

let apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
let searchBox = document.querySelector(".search input");
let searchBtn = document.querySelector(".search button");

async function FetchWeatherDataByCityName(city) {
  const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
  var data = await response.json();
  console.log(data);
  //   handleTemp.innerHTML =
  //   handleWeatherIcon.innerHTML = data.weather[0].main;

  document.querySelector(".city-heading").innerHTML = data.name;
  document.querySelector(".temp-heading").innerHTML =
    Math.round(data.main.temp) + "°C";
  document.querySelector(".weather-icon").innerHTML = data.weather[0].main;
  document.querySelector(".h3-humidity-heading").innerHTML =
    data.main.humidity + "%";
  document.querySelector(".h3-wind-speed").innerHTML =
    data.wind.speed + " Km/h";

  // Choosing the weather icon
  if (data.weather[0].main == "Clouds") {
    document.querySelector(".weather-icon").src = "images/clouds.png";
  } else if (data.weather[0].main == "Clear") {
    document.querySelector(".weather-icon").src = "images/clear.png";
  } else if (data.weather[0].main == "Drizzle") {
    document.querySelector(".weather-icon").src = "images/drizzle.png";
  } else if (data.weather[0].main == "Mist") {
    document.querySelector(".weather-icon").src = "images/mist.png";
  } else if (data.weather[0].main == "Rain") {
    document.querySelector(".weather-icon").src = "images/rain.png";
  } else if (data.weather[0].main == "Snow") {
    document.querySelector(".weather-icon").src = "images/snow.png";
  }
}

searchBtn.addEventListener("click", () => {
  FetchWeatherDataByCityName(searchBox.value);
});

// Here is the html code. Adding some text to balance the code to text ratio for submitting the question. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.:
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Weather App</title>
    <link rel="stylesheet" href="./styles.css" />
    <script src="./index.js"></script>
  </head>
  <body class="body-styles">
    <div class="weather-app-card">
      <div class="input-and-search-icon-styling">
        <div class="search">
          <input
            class="search-input"
            type="text"
            placeholder="Enter City Name"
          />
        </div>
        <div class="search">
          <button class="search-icon-btn">
            <img class="search-icon" src="./images/search.png" alt="" />
          </button>
        </div>
      </div>
      <div class="">
        <img class="weather-icon" src="./images/clear.png" alt="" />
      </div>
      <div>
        <h1 class="temp-heading">7°C</h1>
        <h2 class="city-heading">New York</h2>
      </div>
      <div class="humidity-and-wind-speed">
        <div class="humidity-icon-and-text">
          <div>
            <img class="humidity-image" src="./images/humidity.png" alt="" />
          </div>
          <div class="humidity-percentage">
            <h3 class="h3-humidity-heading">48%</h3>
            <h4 class="h4-humidity">Humidity</h4>
          </div>
        </div>
        <div class="wind-speed-icon-and-text">
          <div>
            <img class="wind-image" src="./images/wind.png" alt="" />
          </div>
          <div>
            <h3 class="h3-wind-speed">10.29Km/h</h3>
            <h4 class="h4-wind-speed">wind speed</h4>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

4

Answers


  1. Try with this javascript code

    document.addEventListener("DOMContentLoaded", () => {
      let apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
      let searchBox = document.querySelector(".search input");
      let searchBtn = document.querySelector(".search button");
    
      async function FetchWeatherDataByCityName(city) {
        const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
        const data = await response.json();
        console.log(data);
    
        document.querySelector(".city-heading").innerHTML = data.name;
        document.querySelector(".temp-heading").innerHTML =
          Math.round(data.main.temp) + "°C";
        document.querySelector(".weather-icon").innerHTML = data.weather[0].main;
        document.querySelector(".h3-humidity-heading").innerHTML =
          data.main.humidity + "%";
        document.querySelector(".h3-wind-speed").innerHTML =
          data.wind.speed + " Km/h";
    
        // Choosing the weather icon
        if (data.weather[0].main == "Clouds") {
          document.querySelector(".weather-icon").src = "images/clouds.png";
        } else if (data.weather[0].main == "Clear") {
          document.querySelector(".weather-icon").src = "images/clear.png";
        } else if (data.weather[0].main == "Drizzle") {
          document.querySelector(".weather-icon").src = "images/drizzle.png";
        } else if (data.weather[0].main == "Mist") {
          document.querySelector(".weather-icon").src = "images/mist.png";
        } else if (data.weather[0].main == "Rain") {
          document.querySelector(".weather-icon").src = "images/rain.png";
        } else if (data.weather[0].main == "Snow") {
          document.querySelector(".weather-icon").src = "images/snow.png";
        }
      }
    
      // Check if searchBtn and searchBox are not null before adding event listener
      if (searchBtn && searchBox) {
        searchBtn.addEventListener("click", () => {
          FetchWeatherDataByCityName(searchBox.value);
        });
      } else {
        console.error("Search button or search input not found.");
      }
    });
    Login or Signup to reply.
  2. Most likely cause

    Your JS is trying to access an element in your page at a point in time, when the browser hasn’t parsed the page yet. This commonly happens if you put your external <script src="/path/to/your.js"></script> in the <head> of the page.

    When doing so, the browser stops parsing at that point to load the JavaScript referenced in the src-attribute of the <script>-tag, and executes it immediately. At this point no element below that <script>-tag in the HTML document is accessible to JS.

    3 way to fix

    1. The easiest fix in this scenario is to put a defer attribute on the <script>-tag:
      <script src="/path/to/your.js" defer></script>
      
    • This will allow the browser to load the referenced JS file, but wait until the whole page is parsed before it runs the code.
    1. Wrap your code in a DOMContentLoaded listener:
      document.addEventListener('DOMContentLoaded', () => {
        // move your code here
      });
      
    • This will run the code once the browser issues the event that notifies code listening for it that the parsing of the page is completed.
    1. Move the <script>-tag to the end of the document, right before the closing </body>-tag. This way the browser only encounters your script when everything else in the body has already been parsed, since browsers parse documents top-down.

    Other possible causes

    If you’re already making sure your JS isn’t executed too early, another possible cause for your error could be that your querySelector are trying to select an element in the page based on a selector that doesn’t match anything inside your HTML structure.

    Login or Signup to reply.
  3. You need to wrap it in a load event handler

    Here is a simpler working version using your HTML where I fixed some icon issues too

    document.addEventListener('DOMContentLoaded', () => {
      const apiKey = "bd5e378503939ddaee76f12ad7a97608"; // found on the internet, please change for your own
      let apiUrl = "https://api.openweathermap.org/data/2.5/weather?units=metric&q=";
      let form = document.querySelector(".search");
      let searchBox = form.querySelector("input");
    
      async function FetchWeatherDataByCityName(city) {
        const response = await fetch(apiUrl + city + `&appid=${apiKey}`);
        var data = await response.json();
        console.log(data);
        //   handleTemp.innerHTML =
        //   handleWeatherIcon.innerHTML = data.weather[0].main;
    
        document.querySelector(".city-heading").innerHTML = data.name;
        document.querySelector(".temp-heading").innerHTML = Math.round(data.main.temp) + "°C";
        document.querySelector(".h3-humidity-heading").innerHTML = data.main.humidity + "%";
        document.querySelector(".h3-wind-speed").innerHTML = data.wind.speed + " Km/h";
    
        // Choosing the weather icon
        const iconSrc = data.weather[0].main;
        const icon = document.querySelector(".weather-icon");
        icon.src = ["Clouds", "Clear", "Drizzle", "Mist", "Rain", "Snow"]
          .includes(icon) ? `images/${icon.toLowerCase()}.png` : `images/unknown.png`;
        icon.alt=iconSrc;
      }
      form.addEventListener("submit", (e) => {
        e.preventDefault();
        const city = searchBox.value;
        FetchWeatherDataByCityName(city); // run on load  - remove if you do not want to do that
      });
      FetchWeatherDataByCityName("New York"); // initial
    });
    <div class="weather-app-card">
      <div class="input-and-search-icon-styling">
        <form class="search">
          <input class="search-input" type="text" placeholder="Enter City Name" value="New York"/>
          <button type="submit" class="search-icon-btn">
                <img class="search-icon" src="./images/search.png" alt="" />
              </button>
        </form>
      </div>
      <div class="">
        <img class="weather-icon" src="./images/clear.png" alt="" />
      </div>
      <div>
        <h1 class="temp-heading"></h1>
        <h2 class="city-heading"></h2>
      </div>
      <div class="humidity-and-wind-speed">
        <div class="humidity-icon-and-text">
          <div>
            <img class="humidity-image" src="./images/humidity.png" alt="" />
          </div>
          <div class="humidity-percentage">
            <h3 class="h3-humidity-heading"></h3>
            <h4 class="h4-humidity"></h4>
          </div>
        </div>
        <div class="wind-speed-icon-and-text">
          <div>
            <img class="wind-image" src="./images/wind.png" alt="" />
          </div>
          <div>
            <h3 class="h3-wind-speed"></h3>
            <h4 class="h4-wind-speed"></h4>
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
  4. The reason why querySelector cannot find the button is that the JavaScript code is being executed before the elements in the body are fully loaded.

    1. Include the script just before the closing body tag:

    This ensures that the script runs after the entire body has been parsed. (What's the difference between putting script in head and body?)

    <body>
       ...
       <script src="./script.js"></script>
    </body>
    
    1. Use the load event to wait for the whole page to load:

    This ensures that your script runs only after the entire page has been loaded. (https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event).

    addEventListener("load", (event) => {
       // Your code
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search