Home > Net >  JavaScript Array.filter() and .map() don't work, uncaught TypeError for Search function
JavaScript Array.filter() and .map() don't work, uncaught TypeError for Search function

Time:12-03

So I'm trying to implement a search bar in my Flask application that will list out the cities that are being inputted by the user and exist in the JSON API results of a weather API.

I am following a tutorial and basically have the same code as ths: https://codepen.io/jamesqquick/pen/XWJxBQv

However, in my implementation, the .filter() and .map() functions don't work, I get the following error: TypeError for map() and filter()

How do I fix this?

Here's my code (the regular generateHTML in the first part of the code with fetching current weather data already works, only the "SEARCH BAR" section has problems):

let currentType = "current.json";
let userCity = "London";

const apiData = {
    url: "http://api.weatherapi.com/v1",
    type: `${currentType}`,
    key: "40cd513af8aa446484a92837213011",
    city: `${userCity}`,
  };


const { url, type, key, city } = apiData;

const apiUrl = `${url}/${type}?key=${key}&q=${city}`;

console.log("apiUrl:");
console.log(apiUrl);

 fetch(apiUrl)
   .then((data) => {
     if (data.ok) {
       return data.json();
     }
     throw new Error("Response not ok.");
   })
   .then((locationRequest) => generateHtml(locationRequest))
   .catch((error) => console.error("Error:", error));

 const generateHtml = (data) => {
   console.log("data:")
   console.log(data);
   console.log("data.location.name:")
   console.log(`${data.location.name}`);
   const html = `
     <div >
        <h1>${data.location.name}, ${data.location.country}</h1></div>
     <div >
         <span>Tmp: ${data.current.temp_c} °C</span>
         <span>Feels like: ${data.current.feelslike_c} °C</span>
     </div>
 `;
   const weatherDiv = document.querySelector(".weather");
   weatherDiv.innerHTML = html;
};
/* SEARCH BAR */

const citiesList = document.getElementById('weather-cities');
const searchBar = document.getElementById('weather-searchbar');
let cities = [];

console.log("citiesList:");
console.log(citiesList);
console.log("searchBar:");
console.log(searchBar);

searchBar.addEventListener('keyup', (e) => {
    userCity = e.target.value.toLowerCase();
    console.log("usercity:");
    console.log(userCity);
    const filteredCities = cities.filter((city) => {
        return (
            city.name.toLowerCase().includes(userCity) ||
            city.region.toLowerCase().includes(userCity) ||
            city.country.toLowerCase().includes(userCity)
        );
    });
    displayCities(filteredCities);
});

const loadCities = async () => {
    try {
        currentType = "search.json";
        const res = await fetch(apiUrl);
        cities = await res.json();
        console.log("cities:");
        console.log(cities);
        displayCities(cities);
    } catch (err) {
        console.error(err);
    }
};

const displayCities = (cities) => {
    let htmlString = cities
        .map((city) => {
            return `
            <li >
                <h2>${city.location.name}</h2>
                <p>Temperature: ${city.current.temp_c} °C</p>
                <p>Feels like:${city.current.feelslike_c} °C></p>
            </li>
        `;
        })
        .join('');
    citiesList.innerHTML = htmlString;
};

loadCities();
<div class="other-stats">
    <div class="weather-search">
      <input type="text" id="weather-searchbar" placeholder="Your city"></input>
      <ul id="weather-cities"></ul>
    </div>
    <div class="weather"></div>
  </div>
  <script src="../static/weather_api.js"></script>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Array.prototype.filter() and Array.prototype.map() are used for arrays, the cities property is getting a javascript object. You need to assign an array to "cities".

CodePudding user response:

Ok, it seems I solved the issue for now. In displayCities, for the HTML section I put city.location.name like I'd do to get the name in "current.json" API call, but in the new API call "search.json" I get an array of dictionaries that contain different information directly, not with different categories like "location" or "current". So city.name is enough. To clarify better, see console.log entries:

API call "current.json"

API call "search.json"

const displayCities = (cities) => {
    let htmlString = cities
        .map((city) => {
            return `
            <li >
                <p>${city.name}</p>
            </li>
        `;
        })
        .join('');
    citiesList.innerHTML = htmlString;
};
  • Related