Home > OS >  Uncaught (in promise) TypeError: Cannot set properties of null (setting 'innerHTML')
Uncaught (in promise) TypeError: Cannot set properties of null (setting 'innerHTML')

Time:09-10

I spent a good part of yesterday trying to find out what was causing this error but never figured it out. Everything seems to work and I want to go back over and refactor it but the error concerns me. I've tried a number of things (changing variable names / using window.addEventListener / going back to the older version and taking working each step until the error occurs...etc...). Nothing seems to help get rid of it. The error is pretty clear. it says the issue is happening at setupDay.

Uncaught (in promise) TypeError: Cannot set properties of null (setting 'innerHTML') at setupDay (getWeatherInfo.js:37:23)

Here is the code:

getWeatherInfo.js



import { FetchWrapper } from "./fetchWrapper.js";

const apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const unit = "imperial";
const form = document.querySelector("#weatherForm");
const zip = document.querySelector("#zipcode");
const country = "us";

// Event listener for form submit
form.addEventListener("submit", (event) => {
  event.preventDefault();
  getWeatherInfo(zip.value);
});

const geoAPI = new FetchWrapper("https://api.openweathermap.org/geo/1.0/");
const API = new FetchWrapper("https://api.openweathermap.org/data/2.5/");

const getWeatherInfo = (zip) => {
  const endpoint = `zip?zip=${zip},${country}&appid=${apiKey}&units=${unit}`;
  geoAPI.get(endpoint).then((data) => {
    const lat = data.lat;
    const lon = data.lon;
    const weatherEndpoint = `weather?lat=${lat}&lon=${lon}&appid=${apiKey}&units=${unit}`;
    const fiveDayEndpoint = `forecast?lat=${lat}&lon=${lon}&appid=${apiKey}&units=${unit}`;

    // ----------------- Current Weather ----------------- //

    API.get(weatherEndpoint).then((data) => {
      
      function setupDay(value) {
        let tempValue = document.querySelector("#weather-body-temp-value");
        tempValue.innerHTML = value.main.temp;

        let feelsLike = document.querySelector("#weather-body-feels-like-value");
        feelsLike.innerHTML = value.main.feels_like;

        let weatherDescription = document.querySelector("#weather-body-description");
        weatherDescription.innerHTML = value.weather[0].description;

        let weatherIcon = document.querySelector("#weather-body-description-icon");
        weatherIcon.innerHTML = `<img src="http://openweathermap.org/img/wn/${value.weather[0].icon}@2x.png">`;

        let windSpeed = document.querySelector("#weather-body-wind-value");
        windSpeed.innerHTML = value.wind.speed;

        let cityName = document.querySelector("#weather-body-city-value");
        cityName.innerHTML = value.name;

        let sunrise = document.querySelector("#weather-body-sunrise-value");
        sunrise.innerHTML = unixTimeConvertor(value.sys.sunrise);

        let sunset = document.querySelector("#weather-body-sunset-value");
        sunset.innerHTML = unixTimeConvertor(value.sys.sunset);
      }
  
      setupDay(data);
    });

    // ----------------- 5 Day Forecast ----------------- //

    API.get(fiveDayEndpoint).then((data) => {
      const day1 = data.list[0];
      const day2 = data.list[8];
      const day3 = data.list[16];
      const day4 = data.list[24];
      const day5 = data.list[32];
      
      function setupDays (value, dayNumber)  {
        let temperature = document.querySelector("#day"   dayNumber);
        temperature.innerHTML = value.main.temp;

        let humidity = document.querySelector("#day"   dayNumber   "-humidity");
        humidity.innerHTML = value.main.humidity;

        let description = document.querySelector("#day"   dayNumber   "-description");
        description.innerHTML = value.weather[0].description;

        let icon = document.querySelector("#day"   dayNumber   "-icon");
        icon.innerHTML = `<img src="http://openweathermap.org/img/wn/${value.weather[0].icon}@2x.png">`;
      };
      setupDays(day1, 1);
      setupDays(day2, 2);
      setupDays(day3, 3);
      setupDays(day4, 4);
      setupDays(day5, 5);
    });
  });
};

const unixTimeConvertor = (unixTimestamp) => {
  const dateObject = new Date(unixTimestamp * 1000);
  const date = dateObject.toLocaleString("en-US", {
    hour: "numeric",
    minute: "numeric",
    second: "numeric",
  });
  return date;
};

fetchWrapper.js

//fetchwrapper.js
export class FetchWrapper {
  constructor(baseURL) {
    this.baseURL = baseURL;
  }

  get(endpoint) {
    return fetch(this.baseURL   endpoint).then((response) => {
      return response.json();
    });
  }
}

getFiveDayWeather.html


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <!-- <link href="index.css" rel="stylesheet" type="text/css" /> -->
  <link href="getFiveDayWeather.css" rel="stylesheet" type="text/css" />
  <title>Open Weather API</title>
</head>

<body>
  <nav>
    <ul >
      <li><a href="index.html">Home</a></li>
      <li><a href="projects.html">Projects</a></li>
      <li><a href="about.html">About</a></li>
    </ul>
  </nav>
  <h2>Open Weather API Project</h2>
  <form id="weatherForm">
    <input type="text" id="zipcode" placeholder="Enter zip code" />
    <input type="submit" value="Submit" />
  </form>
  <a href="getCurrentWeather.html">Get Current Weather</a>
  <!-- 5 day forcast table -->
  <div id="weather-container">
    <table>
      <caption>
        <h2>Five Day Forecast</h2>
      </caption>
      <!-- table header x axis -->
      <tr>
        <th height="70px" width="250">5 Day Forecast</th>
        <th height="70px" width="250">Avg. Temp.</th>
        <th height="70px" width="250">Humidity %</th>
        <th height="70px" width="250">Weather Desc.</th>
      </tr>

      <!-- table header y axis -->
      <tr>
        <th height="70px">Day 1</th>
        <td>
          <p id="day1"></p>
        </td>
        <td>
          <p id="day1-humidity"></p>
        </td>
        <td>
          <p id="day1-description"></p>
          <p id="day1-icon"></p>
        </td>
      </tr>

      <tr>
        <th height="70px">Day 2</th>
        <td>
          <p id="day2"></p>
        </td>
        <td>
          <p id="day2-humidity"></p>
        </td>
        <td>
          <p id="day2-description"></p>
          <p id="day2-icon"></p>
        </td>

      </tr>

      <tr>
        <th height="70px">Day 3</th>
        <td>
          <p id="day3"></p>
        </td>
        <td>
          <p id="day3-humidity"></p>
        </td>
        <td>
          <p id="day3-description"></p>
          <p id="day3-icon"></p>
        </td>
      </tr>

      <tr>
        <th height="70px">Day 4</th>
        <td>
          <p id="day4"></p>
        </td>
        <td>
          <p id="day4-humidity"></p>
        </td>
        <td>
          <p id="day4-description"></p>
          <p id="day4-icon"></p>
        </td>
      </tr>

      <tr>
        <th height="70px">Day 5</th>
        <td>
          <p id="day5"></p>
        </td>
        <td>
          <p id="day5-humidity"></p>
        </td>
        <td>
          <p id="day5-description"></p>
          <p id="day5-icon"></p>
        </td>
      </tr>
    </table>

  </div>

  <footer id="footer">
    <a href="https://github.com/jim3" target="_blank" style="color: yellow">
      <li>Github</li>
    </a>
  </footer>

  <script type="module" src="getWeatherInfo.js"></script>
  <script type="module" src="fetchWrapper.js"></script>
  <!-- <script src="fetchWrapper.js"></script> -->
  <!-- <script src="activateStickyFooter.js"></script> -->
</body>

</html>

getCurrentWeather.html


<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link href="getCurrentWeather.css" rel="stylesheet" type="text/css" />
  <title>Open Weather API</title>
</head>

<body>
  <nav>
    <ul >
      <li><a href="index.html">Home</a></li>
      <li><a href="projects.html">Projects</a></li>
      <li><a href="about.html">About</a></li>
    </ul>
  </nav>
  <h2>Open Weather API Project</h2>
  <form id="weatherForm">
    <input type="text" id="zipcode" placeholder="Enter zip code" />
    <input type="submit" value="Submit" />
  </form>
  <a href="getFiveDayWeather.html">Get Five Day Forecast</a>
  <!-- start of weather container -->
  <div id="weather-container">
    <table>
      <caption>
        <h3>Current Weather Info<h3>
      </caption>
      <tr>
        <th>City</th>
        <td>
          <p id="weather-body-city-value"></p>
        </td>
      </tr>
      <tr>
        <th>Temperature</th>
        <td>
          <p id="weather-body-temp-value"></p>
        </td>
      </tr>
      <tr>
        <th>Feels Like</th>
        <td>
          <p id="weather-body-feels-like-value"></p>
        </td>
      </tr>

      <tr>
        <th>Description</th>
        <td>
          <p id="weather-body-description"></p>
          <p id="weather-body-description-icon"></p>
        </td>
      </tr>

      <tr>
        <th>Wind Speed</th>
        <td>
          <p id="weather-body-wind-value"></p>
        </td>
      </tr>
      <tr>
        <th>Sunrise</th>
        <td>
          <p id="weather-body-sunrise-value"></p>
        </td>
      </tr>
      <tr>
        <th>Sunset</th>
        <td>
          <p id="weather-body-sunset-value"></p>
        </td>
      </tr>
    </table>
  </div>
  <script type="module" src="getWeatherInfo.js"></script>
  <script type="module" src="fetchWrapper.js"></script>
  <!-- <script src="fetchWrapper.js"></script> -->
</body>

</html>

CodePudding user response:

You have two HTML pages whose elements have different IDs, but from JavaScript you try to fetch all elements unconditionally.

If you're on getFiveDayWeather.html then setupDay() will fail because there's no #weather-body-temp-value, and if you're on getCurrentWeather.html then setupDays() will fail because there's no #day1.

The reason it still works is because these errors happen within promise callbacks, so they terminate the function they occur in, but don't affect the rest of the code.

In order to fix this, find a way to run only either API.get(weatherEndpoint) or API.get(fiveDayEndpoint), conditionally based on which HTML page you're on. An example that isn't particularly pretty but should work fine could look like this:

if(document.querySelector("#weather-body-temp-value"))
{
  // ----------------- Current Weather ----------------- //
  API.get(weatherEndpoint).then((data) => {
    ...
  });
}
else if(document.querySelector("#day1"))
{
  // ----------------- 5 Day Forecast ----------------- //
  API.get(fiveDayEndpoint).then((data) => {
    ...
  });
}
else
{
  // Throw an error or show an alert or something
}
  • Related