ReferenceError: API is not defined (Javascript) - javascript

I'm trying to make an App for meteo, but my api doesn't load.
When i call API in fetch it output: ReferenceError: API is not defined
It is my first app (also my first question on StackOverflow), this is the snippet:
window.addEventListener('load', () =>{
let long;
let lang;
let temperatureDescription = document.querySelector('.temperature-description');
let temperatureDegree = document.querySelector('.temperature-degree');
let locationTimezone = document.querySelector('.location-timezone');
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position=>{
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = 'https://cors-anyware.herouapp.com/';
const API = '${proxy}https://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=cc6a4a00070dfbee1327390b072f88d6/${lat},${long}';
});
fetch(API).then(response=>{
return response.json();
}).then(data=>{
console.log(data);
const {
temperature,
summary
}
= data.currently;
//set DOM elements from the API
temperatureDegree.textContent = temperature;
});
};
}
);
Can anyone help me?
Thanks :)

Your API constant variable is block scoped, it means that it is accessible only inside of callback of getCurrentPosition function.
And also,navigator.geolocation.getCurrentPosition is asynchronous, you should call fetch inside the callback. otherwise fetch will execute before location lat lon is detected by browser.
window.addEventListener('load', () =>{
let long;
let lang;
let temperatureDescription = document.querySelector('.temperature-description');
let temperatureDegree = document.querySelector('.temperature-degree');
let locationTimezone = document.querySelector('.location-timezone');
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position=>{
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = 'https://cors-anyware.herouapp.com/';
const API = '${proxy}https://api.openweathermap.org/data/2.5/forecast?id=524901&APPID=cc6a4a00070dfbee1327390b072f88d6/${lat},${long}';
fetch(API).then(response=>{
return response.json();
}).then(data=>{
console.log(data);
const {
temperature,
summary
}
= data.currently;
//set DOM elements from the API
temperatureDegree.textContent = temperature;
});
});
};
}
);

Related

cannot render an ejs page with variables from axios api call

I have seen the others questions about this topic, but my problem is slightly different: I have an axios call inside the .then of another axios call, and then I take values from the API that I called with axios and in another .then I render an ejs page, but the first time I execute, it tries to render the page before axios calling are completed, so variable to build the page are undefined, in particular it prints the error 'h1 is undefined' and h1 is the first variable in the ejs document after nameCapitalized which, as you can see from the code, is form the request and not from the axios api call; from the second time it works perfectly, when it works, it prints in order the console.log statements in .then, so the execution order is right, at least from the second execution. This get request is made after clicking a link in the browser.
Here the code:
app.get('/private_:city/', function(req, response) {
const name = req.params.city;
const nameCapitalised = name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
let lat;
let lon;
let country;
let jsonObj;
let h1;
let w1;
let t1;
let uv1;
let rp1;
let ws1;
axios.get(`http://api.openweathermap.org/geo/1.0/direct?q=${nameCapitalised}&limit=1&appid=${apiKeyOpenWeather}`)
.then(res => {
console.log('first');
lat = res.data[0].lat;
lon = res.data[0].lon;
country = res.data[0].country;
console.log(res.data[0]);
axios.get(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&exclude=daily,minutely&units=metric&lang=it&appid=${apiKeyOpenWeather}`)
.then(res => {
console.log('second');
jsonObj = res.data;
h1 = new Date(jsonObj.hourly[0].dt * 1000).getHours();
w1 = jsonObj.hourly[0].weather[0].description;
t1 = jsonObj.hourly[0].temp;
uv1 = jsonObj.hourly[0].uvi;
rp1 = Math.trunc(jsonObj.hourly[0].pop * 100);
ws1 = jsonObj.hourly[0].wind_speed;
})
.then(res => {
console.log('third');
response.render('private.ejs', {
title: nameCapitalised,
t1: t1,
h1: h1,
w1: w1,
uv1: uv1,
rp1: rp1,
ws1: ws1,
});
});
});
});
Try to use only thens...
app.get('/private_:city/', function(req, response) {
const name = req.params.city;
const nameCapitalised = name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
let lat;
let lon;
let country;
let jsonObj;
let h1;
let w1;
let t1;
let uv1;
let rp1;
let ws1;
axios.get(`http://api.openweathermap.org/geo/1.0/direct?q=${nameCapitalised}&limit=1&appid=${apiKeyOpenWeather}`)
.then(async (res) => {
console.log('first');
lat = res.data[0].lat;
lon = res.data[0].lon;
country = res.data[0].country;
console.log(res.data[0]);
return await axios.get(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&exclude=daily,minutely&units=metric&lang=it&appid=${apiKeyOpenWeather}`)})
.then(res => {
console.log('second');
jsonObj = res.data;
h1 = new Date(jsonObj.hourly[0].dt * 1000).getHours();
w1 = jsonObj.hourly[0].weather[0].description;
t1 = jsonObj.hourly[0].temp;
uv1 = jsonObj.hourly[0].uvi;
rp1 = Math.trunc(jsonObj.hourly[0].pop * 100);
ws1 = jsonObj.hourly[0].wind_speed;
})
.then(res => {
console.log('third');
response.render('private.ejs', {
title: nameCapitalised,
t1: t1,
h1: h1,
w1: w1,
uv1: uv1,
rp1: rp1,
ws1: ws1,
});
});
});
});
I think you should try to change variables order in the ejs document in order to understand if it is a problem of 'h1'

Why doesn't this JS code run on older devices?

I'm trying to build a simple MagicMirror in-browser weather app based on openweathermap API.
Knowing very little about coding, it proves a bit hard. I have this code, that someone corrected for me, but it won't run on older devices. Here's the sandbox link.
class Weather {
constructor(data) {
this.data = data;
this.temp = Math.round(data.main.temp);
this.feels_like = Math.round(data.main.feels_like);
this.description = data.weather[0].description;
this.city = data.name;
this.country = data.sys.country;
this.wind = Math.round(data.wind.speed);
this.humidity = data.main.humidity;
}
geticonClass() {
let prefix = this.data.weather[0].icon.endsWith("d")
? 'wi-owm-day-'
: 'wi-owm-night-';
return `${prefix}${this.data.weather[0].id}`;
}
}
function fetchWeather() {
navigator.geolocation.getCurrentPosition(
async (position) => {
let url = new URL("https://api.openweathermap.org/data/2.5/weather");
url.searchParams.set("lat", position.coords.latitude);
url.searchParams.set("lon", position.coords.longitude);
url.searchParams.set("lang", "pl");
url.searchParams.set("appid", "fb7164d50e0faf1f058561b7903f03b9");
url.searchParams.set("units", "metric");
const response = await fetch(url);
const weatherJSON = await response.json();
updateDOM(new Weather(weatherJSON));
},
(error) => {
console.error("Unable to get geolocation, Unsuported maybe?");
}
);
}
function updateDOM(weather) {
const iconElement = document.querySelector(".today-weather-icon i");
const tempElement = document.querySelector(".temperature-value p");
const tempFeelElement = document.querySelector(".temperature-feel p");
const descElement = document.querySelector(".temperature-description p");
const locationElement = document.querySelector(".location p");
const windElement = document.querySelector(".wind p");
const humidElement = document.querySelector(".humid p");
iconElement.classList.add(weather.geticonClass());
tempElement.innerHTML = `${weather.temp}°<span>C</span>`;
tempFeelElement.innerHTML = `Odczuwalna: ${weather.feels_like}°<span>C</span>`;
descElement.innerHTML = weather.description;
locationElement.innerHTML = `${weather.city}, ${weather.country}`;
windElement.innerHTML = ` ${weather.wind} km/h`;
humidElement.innerHTML = ` ${weather.humidity}`;
}
fetchWeather();
setInterval(fetchWeather, 1800000);
updateDOM();
setInterval(updateDOM, 1820000);
Here's a previous version of the code with navigator.geolocation that worked.
You are using modern ES6 syntax for example class Weather that's why. If you want to learn more about how you can convert it to pre ES6 syntax so it works on older devices too check this article ES6 Class vs Object.prototyoe
`

javascript data visualization using bar graphs

I am trying to do data visualization using javascript to construct bar graphs. I am encountering problems when trying to render the graphs. I keep getting the message 'TypeError: rates is not iterable' in the console which refers to the for loop in the render function. Any idea how to fix this problem?
Thanks!
Here's my code:
console.log('running js for currency rates');
doFetch()
function doFetch(){
fetch('https://api.exchangeratesapi.io/latest')
.then(response => response.json())
.then(data => {
console.log('Got the data!');
console.log(data);
let rates = data.rates;
let base = data.base;
let date = data.date;
console.log(rates);
render(rates)
});
}
function render(rates){
const currencyName = Object.keys(rates);
const values = Object.values(rates);
let chart = document.querySelector('.BarContainer');
chart.innerHTML = "";
for(let rate of rates){
let bar = document.createElement('div');
let baseHeight = 100;
bar.classList.add('Bar');
bar.style.height = baseHeight + 'px';
bar.textContent = currencyName;
chart.appendChild(bar);
}
}
for/of works on iterables, and an Object isn't iterable. You might be looking for for/in.
for/of
for/in
Because rates are literal object. And for of works for Javascript Array. I think you need to use for in instead.
Here is what should be
<!doctype html>
<html>
<body>
<div class="BarContainer"></div>
</body>
<script type='text/javascript'>
console.log('running js for currency rates');
doFetch()
function doFetch(){
fetch('https://api.exchangeratesapi.io/latest')
.then(response => response.json())
.then(data => {
console.log('Got the data!');
console.log(data);
let rates = data.rates;
let base = data.base;
let date = data.date;
console.log(rates);
render(rates)
});
}
function render(rates){
const currencyName = Object.keys(rates);
const values = Object.values(rates);
let chart = document.querySelector('.BarContainer');
chart.innerHTML = "";
for(let rate in rates){
let bar = document.createElement('div');
let baseHeight = 100;
bar.classList.add('Bar');
bar.style.height = baseHeight + 'px';
bar.textContent = currencyName;
chart.appendChild(bar);
}
}
</script>
<html>

How to fetch api from the function which pushes each api in array?

I am trying to get API data so i can render it on Webpage using ReactJS. I tried many different ways to fetch api where its stored in array. But i am unable to do it.
Note:https://www.hatchways.io/api/assessment/workers/<worker_id> Here i'm looping so the
worker id gets add the of url.
const fetchAPI = e => {
let array = [];
const api2 = `https://www.hatchways.io/api/assessment/workers/`;
for (var i = 0; i <= 4; i++) {
array.push(api2 + i);
}
return array;
};
console.log(fetchAPI());
Thanks in advance.
You need to hit the url first. Async/Await would be a good choice.
<script>
async function check()
{
var arrayData =[];
var url = "https://www.hatchways.io/api/assessment/workers/";
for(var i=1;i<=4;i++)
{
const response = await fetch(url+""+i);
const myJson = await response.json();
arrayData.push(myJson);
}
console.log(arrayData)
}
check();
</script>
Use Promise.all for example:
const baseURL = 'https://jsonplaceholder.typicode.com';
const fetchUsers = fetch(`${baseURL}/users`);
const fetchPosts = fetch(`${baseURL}/posts`);
Promise.all([fetchUsers, fetchPosts]).then((responses) => {
const responsesToJson = responses.map(response => response.json());
return Promise.all(responsesToJson);
}).then((jsonResponse) => {
const [userResponse, postResponse] = jsonResponse;
console.log(userResponse);
console.log(postResponse);
});

Nodejs: How to avoid nested .then() when using async/await

Following is what I'm trying to do this in nodejs. The Rest API takes a city name as an input. I am trying to get the latitude and longitude using the geocode API for the input city. then, using the latitude and longitude, I am trying to get a list of closest cities using another API. then, for all those cities, I am getting the weather report, then for those cities, I am getting whether there is water and I am returning this back as a JSON.
As you can see, there is a lot of then and the goal of this exercise is to avoid nested callbacks.
I am using async/await which is supposed to have eliminated the nested then functions. But I don't see another way of doing this. The complete code snippet is below. The ugly part I am trying to fix is requester.makeRequest()
Following is just a snippet of the necessary code and not the complete working code. Any help on how to untangle this would be greatly appreciated.
app.get('/search', function(req, res, next) {
const requester = {
lastRequest: new Date(),
makeRequest: async function(url) {
const response = await fetch(url);
const json = await response.json();
return json;
}
};
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token)
.then(function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long)
.then(function(closer_cities) {
var cities_len = closer_cities.length
for(i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
requester.makeRequest(woeid_url + woeid)
.then(function(weather) {
var lattlong = weather.latt_long;
requester.makeRequest(onwater_url+ lattlong +
'?access_token=' + water_access_token)
.then(function(onwater) {
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({error: false,
data: {message: final_result}})
}
})
})
}
})
})
})
I would say you still need one then
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token)
.then(async function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
closer_cities = await requester.makeRequest(metaweather_url + '?lattlong='+ lat + ',' + long);
var cities_len = closer_cities.length;
for(i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
weather = await requester.makeRequest(woeid_url + woeid)
var lattlong = weather.latt_long;
onwater = await awaitrequester.makeRequest(onwater_url+ lattlong + '?access_token=' + water_access_token)
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({error: false, data: {message: final_result}})
}
}
})
Edit: I don't really think my answer is relevant for your problem sorry
for this line : requester.makeRequest ... .then(function(city){
replace .then(function(city){ with var city = await requester.makeRequest , city will have the fulfilled value of the promise, do this for the rest of thens :
( keep in mind that await is only used inside an async function, you can use an iife )
(async () => {
var city = await requester.makeRequest(`${geocode_url}?locate=${req.query.q}&json=1${geocode_token}`);
var final_result = []
var lat = city.latt;
var long = city.longt;
// request to get list of cities closer to that location,
//takes latitude and longitude as parameters
var closer_cities = await requester.makeRequest(`${metaweather_url}?lattlong=${lat},${long}`);
var cities_len = closer_cities.length;
for (i = 0; i < closer_cities.length; i++) {
woeid = closer_cities[i].woeid
//request to get weather using woeid parameter
var weather = await requester.makeRequest(woeid_url + woeid);
var lattlong = weather.latt_long;
var onwater = await requester.makeRequest(`${onwater_url}${lattlong}?access_token=${water_access_token}`);
var temp = Object.assign(weather, onwater)
final_result.push(temp)
if (final_result.length == cities_len) {
res.status(200).json({
error: false,
data: {
message: final_result
}
})
}
}
})();
then is misused in the first place because it results in callback hell. Promises are callback-based but they support chaining which is supposed to eliminate nested callbacks.
It should be:
requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1` + geocode_token)
.then(function(city){
var final_result = []
var lat = city.latt;
var long = city.longt;
return requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long)
})
.then(function(closer_cities) {
...
});
If there's a promise inside then, it should be returned. This way there's no more than a single level of callback nesting.
await is syntactic sugar for then, and rejections should be handled as well:
app.get('/search', function(req, res, next) {
try {
...
const city = await requester.makeRequest(geocode_url +`?locate=${req.query.q}&json=1`
+ geocode_token);
var final_result = []
var lat = city.latt;
var long = city.longt;
const closer_cities = await requester.makeRequest(metaweather_url + '?lattlong='
+ lat + ',' + long);
...
} catch (err) {
next(err)
}
});
When calling async functions you are not supposed to use .then(...) construct...
Simply let result = await myAsynchronousFunction(a, b, c); ...

Categories