How do i execute fetch() before other funcitons? - javascript

I'm currently learning JavaScript, and has been playing around with API's (Yahoo Finance in this example).
The goal is to update a table of values with a specific stock's financial data - but I need to fetch the data, before it updates the data. Thought I could use await/async as shown, but it doesn't work.
Any pointers?
let stats;
let inputSymbol;
let stockName;
let stockSymbol;
let stockPrevClose;
let stockOpen;
let stockMarketCap;
let stockDayHigh;
function getStockStatistics(){
//Get symbol from input field
inputSymbol = document.getElementById("inputSymbol").value;
console.log(inputSymbol);
request();
updateStockTabel();
}
//Fetch data from Yahoo Finance API based on variables
const request = async () => {
const response = await fetch(`https://apidojo-yahoo-finance-v1.p.rapidapi.com/stock/v2/get-financials?symbol=${inputSymbol}&region=US`, {
"method": "GET",
"headers": {
"x-rapidapi-key": "---",
"x-rapidapi-host": "---"
}
});
const data = await response.json();
stats = data;
console.log(data);
}
//Update statistics in table based on values from Yahoo Finance JSON object
function updateStockTabel() {
//Change properties
stockPrevClose = stats.summaryDetail.previousClose.raw;
stockOpen = stats.summaryDetail.open.raw;
stockMarketCap = stats.summaryDetail.marketCap.fmt;
stockDayHigh = stats.price.regularMarketDayHigh.fmt;
stockName = stats.price.longName;
stockSymbol = stats.meta.symbol;
//Connect document properties with variables
document.getElementById("stocPrevClose").innerText = stockPrevClose;
document.getElementById("stockOpen").innerText = stockOpen
document.getElementById("stockMarketCap").innerText = stockMarketCap;
document.getElementById("dayHigh").innerText = stockDayHigh;
document.getElementById("stockName").innerText = stockName;
document.getElementById("stockSymbolOutput").innerText = stockSymbol;
}

You have 2 options mainly: leave your code exactly as it is now, but use this to wait to run updateStockTabel :
request().then(() => updateStockTabel());
OR change your getStockStatistics to an async function to do something pretty similar, but with async/await syntax:
async function getStockStatistics(){
//Get symbol from input field
inputSymbol = document.getElementById("inputSymbol").value;
console.log(inputSymbol);
await request();
updateStockTabel();
}

Related

How to render RapidAPI data on another HTML page?

I am new to JavaScript and this is my first question here. I've been trying for week to render my RapidApi data on another HTML page. I made search form on my index page and then put its values as my api call parameters in order to influence my API response. I used fetch to do so. The issue is that my API data keeps rendering on the same index page which is understandable since I don't know how to render it on a separate page. This also means that my CSS styling options are limited since I cannot design API data as I want without messing up my index page. If you have any sort of solution that is not way too complicated I would really appreciate your help.
Here is part of my code:
const input = document.getElementById(`location`);
const guests = document.getElementById(`guests`);
const check = document.querySelectorAll(".date");
let id;
document.getElementById(`submit`).addEventListener(`click`, function (e) {
e.preventDefault();
locationId();
});
async function locationId () {
let hotelId = input.value;
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '//API key goes here',
'X-RapidAPI-Host': 'tripadvisor16.p.rapidapi.com'
}
};
let response = await fetch(`https://tripadvisor16.p.rapidapi.com/api/v1/hotels/searchLocation?query=${hotelId}`, options);
if (!response.ok) throw new Error(`Woops something went wrong`);
let data = await response.json();
let geoId = await (data.data[0].geoId);
id= parseInt(geoId);
return (fetch(`https://tripadvisor16.p.rapidapi.com/api/v1/hotels/searchHotels?geoId=${id}&checkIn=${check[0].value}&checkOut=${check[1].value}&pageNumber=1&adults=${guests.value}currencyCode=USD`, options))
.then(response => response.json())
.then(data => {
let list = data.data.data;
displayObjectElements(list)
function displayObjectElements (object) {
let display = ``;
let price = ``;
object.forEach(element => {
display+= `<div class = "objectResults">
<ul class="hotel__lists">
<li><h2 class = "title">${element.title}</h2></li>
<li><img class= "hotels--photo "src="${element.cardPhotos[0].sizes.urlTemplate.split("?")[0] + `?w=500&h=500`}" alt=image--photo/></li>
<li><p>Ranking:${element.bubbleRating.rating}&#9734 out of 5&#9734</p></li>`
if(!element.priceForDisplay) {
display+= `<li><p>There is no price to display</p></li>`
display+= `<li><button class="booking-btn">Click to book</button></li>`
} else {
price =element.priceForDisplay.substring(1);
price= parseInt(price);
// console.log(price);
display+= `<li><p>Price: $${price} in total</p></li>`
display+= `<li><button class = "booking-btn">Click to book</button></li>
</ul>
</div>`
// console.log(display);
}});
document.body.innerHTML = display;
}
})
.catch(err => console.error(err));
}
I already tried with localStorage and sessionStorage but as a newbie I am just now sure how to put the whole API data in storage. Also, I desperately tried with window.location object as well but as I assumed that did nothing but open a new tab. Again, thanks in advance for any help!

Fetch API prints promise in incorrect order

I am trying to fetch the HTML script of two webpages using their URLs. This is my code:
const links = ["url1" : "https://.......", "url2" : "https://......"];
var responses = [];
for(const [key,value] of Object.entries(links)){
let resp = fetch('https://api.codetabs.com/v1/proxy?quest='+value)
responses.push(resp);
}
Promise.all(responses)
.then( htmlfiles =>{
htmlfiles.forEach(file=>{
file.text().then(function(data){
gethtmldata(data);
})
})
})
In my function gethtmldata, I am parsing this data in HTML format:
function gethtmldata(html_data){
var parser = new DOMParser();
var htmldoc = parser.parseFromString(html_data, "text/html");
console.log(htmldoc); //shows data of url2, then url1
}
To my utter surprise, the data of url2 gets printed first, then url1. Why?
It should show the html data of url1 then url2. How do I fix this?
The iterations of your for loop aren't paused when you do file.text().then(function(data){...}. Instead, your loop fires off multiple .text() calls which will complete sometime in the future, with no guaranteed order on which ones will complete first.
You should .push() a Promise that resolves to your .text() data instead when you create resp:
const links = {"url1" : "https://.......", "url2" : "https://......"};
const urls = Object.values(links);
const responses = [];
for(const value of urls){
const txtPromise = fetch('https://api.codetabs.com/v1/proxy?quest='+value).then(resp => resp.text());
responses.push(txtPromise);
}
Promise.all(responses)
.then(htmlData => {
htmlData.forEach(data=>{
gethtmldata(data);
});
});
You can refactor the above by using .map() and async/await like so:
async function fetchHTMLData(urls) {
const promises = urls.map(async url => {
const resp = await fetch('https://api.codetabs.com/v1/proxy?quest='+url);
return resp.text();
});
return Primise.all(promises);
};
async function processHTMLData() {
const links = {"url1" : "https://.......", "url2" : "https://......"};
const urls = Object.values(links);
const htmlArr = await fetchHTMLData(urls);
htmlArr.forEach(htmlStr => {
gethtmldata(htmlStr);
});
}

API Integration - How to extract only values from Object Array using JS?

Need assistance with Javascript - API Integration. I have been trying to pull data off SWAPI (an open API) and fetch the data into our system. I am struggling with something now!
What I am trying to do is get the around 3 country names and get the people's attribute under that country. So fat I was able to get the country names using the following code:
(async () => {
let Name = [];
let Diameter = [];
let Resident = [];
for (i = 1; i < 4; i++) {
const PlanetDetails = await api.makeRequest({
method: 'GET',
url: `https://swapi.dev/api/planets/${[i]}`,
});
Name[i] = PlanetDetails.data.name;
Resident[i] = PlanetDetails.data.residents;
api.setVariable('Name1', Name[1]);
api.setVariable('Name2', Name[2]);
api.setVariable('Name3', Name[3]);
api.setVariable('R1', Resident[1]);
}
})();
But under the countries the residents' attributes are coming up as links like this:
I used POSTMAN here to test. When I click on the links I can see the person's attributes (e.g color, height, name, etc.). But How do I do that in JS?
Thank you
To get the resident's data, you need to make a request to the endpoint and then use the returned data. for example to get the data of the first resident, you can make a request to https://swapi.dev/api/people/1.
This code makes requests for each resident.
(async () => {
let Name = [];
let Diameter = [];
let Resident = [];
for (i = 1; i < 4; i++) {
const PlanetDetails = await api.makeRequest({
method: 'GET',
url: `https://swapi.dev/api/planets/${[i]}`,
});
Name[i] = PlanetDetails.data.name;
Resident[i] = await Promise.all(PlanetDetails.data.residents.map(async(resident) => {
let resident = await api.makeRequest({
method: 'GET',
url: resident,
});
console.log(resident.data); // for visually viewing the result.
return resident.data;
}));
api.setVariable('Name1', Name[1]);
api.setVariable('Name2', Name[2]);
api.setVariable('Name3', Name[3]);
api.setVariable('R1', Resident[1]);
}
})();

how can i access variables values from a netlify function to call API?

hope someone can help me.
I'm trying to deploy a web app on netlify, but i don't know how to call the API the right way, providing the right value.
this is my netlify function file:
const fetch = require('node-fetch');
exports.handler = async event => {
const API_KEY = process.env.API_KEY;
const response = await fetch(`https://api.waqi.info/feed/${process.env.CITY}/?token=${API_KEY}`);
const data = await response.json();
const pass = (body) => {
return {
statusCode: 200,
body: JSON.stringify(body)
}
};
return pass(data);
}
My problem is about providing the right city value to the API call.
i've also tried to make city an env var on netlify, but even if i change its value, the file lambda.js provides me always the same value probably because it runs just one time at the start.
Here's the code in index.js:
let CITY = process.env.CITY;
async function getCityPollution(city) {
let response = await fetch("/.netlify/functions/lambda");
let result = await response.json();
if(response.status == 200 && result.status == 'ok') {
await dataHandler(result);
console.log(result);
} else if (result.status == 'error'){
console.log(`${result.status}: ${result.data}`);
setTimeout(() => {
dataParagraph.innerHTML = `Unfortunately we have no datas for ${city} station (incredible but true),
insert coords to check datas from the nearest station or try with another city.
Go check https://waqi.info/ to see our coverage`;
$("html, body").animate({ scrollTop: document.body.scrollHeight }, "slow");
}
, 50);
} else {
console.log(response.status);
}
}
// getting city input and call output function
let getCity = document.querySelector('#getCity');
getCity.onclick = async () => {
CITY = cityInput.value;
if (!CITY) {
emptyFields(cityInput);
} else {
await getCityPollution(CITY);
coordInput[0].value = '';
coordInput[1].value = '';
console.log(CITY) //it works, the value changes
}
}
Obviously this is the try with the netlify env var. This way i get always the same value.
There's a way to pass the right value of CITY everytime i need it? Even without using env variables.
Thank you in advance

How to do I pass data to a class object in Javascript?

I have a weather app that I'm building to learn ES6 classes and API calls using Fetch. I'm currently passing the returned data from the fetch call at weather.getWeather(pos), to specific methods within a class called UI. The purpose of the class is to maniuplate the returned data in the DOM.
Can I pass the data variable to the UI class constructor so that I can reference it within my UI class methods?
Or is it best practice to only pass in data to the methods that use/need it?
//init weather and ui objects
const weather = new Weather();
const ui = new UI();
const form = document.getElementById("weather-form");
const loco = document.getElementById("location");
loco.addEventListener("click", () => {
output.innerHTML = '';
// Validation
weather.validation(success, weather.error);
function success(pos) {
weather.getWeather(pos)
.then(data => {
ui.currentWeather(data);
ui.forecast(data);
})
.catch(err => console.error(err));
}
});
//2. Weather API Call
async getWeather(pos) {
const crd = pos.coords;
let lat = crd.latitude;
let long = crd.longitude;
//Current weather
let current = await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${long}&appid=${this.key}&units=metric`);
//Forecast
let fiveDay = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&exclude=${this.exclude}&appid=${this.key}&units=metric`)
let now = await current.json();
let forecast = await fiveDay.json();
return {
now,
forecast
}
}

Categories