Call Fetch Data from API once - javascript

Fetch is often used to retrieve data from api. But if you want to retrieve this data in every line of the code file, you have to type fetch again and again and iterate through these data. But if i want to call only part of it for example username. Look example:
fetch ('/ API')
         .then ((res) => res.json ())
         .then ((data) => {
         let output = 'Here is my output<br />';
         data.forEach (function (item)
         {
         output + = `$ {item.username}`;
         })
         document.getElementById ('here'). innerHTML = output;
         })
if i want to call $ {item.username} in each place in the file without calling fetch.
How to save these data in a variabel and call it every time i want.
Sorry for my bad English.

But if you want to retrieve this data in every line of the code file, you have to type fetch again and again and iterate through these data.
You can call fetch one time and keep the response in your local state, things like username usually stay the same so you should not call that endpoint again just to fetch a username because you can take it from your previous response.
It depends on your framework, but you can write window.username = usernameFromFetch on your first call, and you will have access to it every where (which is not the best aproach but it will work).

From what I understand through your question is that you want to access variable item.username globally and from the code it looks to be an array of users with username property.
In this case, you can define a variable object
var data = {
usernames = []
};
before your fetch function and the value will be initialized to an empty array and as soon as you fetch('/API') users you can do something like this
data.forEach (function (item)
{
data.usernames.push(item.username);
})
data.usernames will have your usernames throughout your current JS file.
access by
data.usernames[0]
data.usernames[1]
data.usernames[2] or
let output = 'Here is my output<br />';
data.usernames.forEach(function(username){
output + = `$ {username}`;
})
document.getElementById('here').innerHTML = output;`

You can use a memoization function to save the result:
// Stores in memory pairs of request urls (arguments) and its result
const memo = (callback) => {
const cache = new Map();
return (...args) => {
const selector = JSON.stringify(args);
if (cache.has(selector)) return cache.get(selector);
const value = callback(...args);
cache.set(selector, value);
return value;
};
};
// Memoize the fetch function. This function 'cachedRequest' should be used across your application
const cachedRequest = memo(fetch);
// Your url to call
const URL = "/API";
// First time the fetch is called, the result will be stored in the memory of 'memo' function. Second time its called, it will be retrieved from the previous in memory result and the fetch call wont be done
cachedRequest(URL).then((response) => {
console.log({response});
}).catch((error) => {
console.log({error});
})

Try this using localStorage:
fetch ('/ API')
.then ((res) => res.json ())
.then ((data) => {
// Store
localStorage.setItem("localData", data);
// Retrieve
var data = localStorage.getItem("localData");
let output = 'Here is my output<br />';
data.forEach (function (item)
{
output + = `$ {item.username}`;
})
document.getElementById ('here'). innerHTML = output;
})
Or use sessionStorage:
fetch ('/ API')
.then ((res) => res.json ())
.then ((data) => {
// Store
sessionStorage.setItem("localData", data);
// Retrieve
var data = sessionStorage.getItem("localData");
let output = 'Here is my output<br />';
data.forEach (function (item)
{
output + = `$ {item.username}`;
})
document.getElementById ('here'). innerHTML = output;
})

Related

how to resolve a response multiple times

so i have a fucntion which would return a Value
for example :
let value= function () =>{
//basically getting values from an api
let get = axios.get("example.com").then(res=>{
Value = res
})
// Value is the value that had been retrieved from a Get request from an API
return Value ;
}
module.export = {value}
^^ That is the first file in the secound file i want to get the values of use the them , the problem here that in the first time i use the function :
const first_file = require("./first_file")
first_file.then(res=>{
console.log(res)
})
the first time i use the fucntion very thing would be fine but sometimes in case of an error i would call the function again using try catch method , this would return the same response i got first time
Sorry For the bad explanation
I am not sure to understand what you want. But if a call crash probably you shouldn't do it again.
But if you want to do something whatever it is when your call crash you can use .catch after .then.
Edit your function value to return the axios call.
let value = function () => {
return axios.get("example.com")
}
module.export = {value}
Then you can access it like this :
const first_file = require("./first_file")
first_file.value.then(res=>{
console.log(res)
}).catch(error => {
// For exemple you can log the error, or do whatever you want here
console.log(error)
})

How do I make the output of this Javascript API response global?

I'm trying to receive the output for the following code where the cc variable would log a value into the empty global country variable. Afterwards print it to the console, however it isn't working. How would I make the local variable cc here to global/give the global variable country a value?
var country = '';
fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
var cc = (response.countryCode);
country = cc;
});
console.log(country);
It seems like your problem has to do with the asynchronous nature of your code. Let me explain.
var country = '';
fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
var cc = (response.countryCode);
country = cc;
});
console.log(country);
The fetch function is asynchronous. That's why you need the .then methods. This means that while the fetch function runs, JavaScript doesn't stop the rest of the program, and instead moves on while fetch() runs in the background. Hence, when you console.log(country), it's still of the original value (empty string).
To answer your question, you can use Promises to log the value of cc.
var country = '';
const fetchPromise = fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
var cc = (response.countryCode);
country = cc;
});
Promise.resolve(fetchPromise) // Waits for fetchPromise to get its value
.then(() => console.log(country))
You can find out more about promises at the MDN docs
The problem with your currently call console.log(country) before country is set to response.countryCode.
You could solve this by placing your code inside an async IIFE in the following manner:
(async () => {
const response = await fetch('https://extreme-ip-lookup.com/json/');
const ipData = await response.json();
const country = ipData.countryCode;
// place all code that uses `country` in here
console.log(country);
})();
If you have another script with function definitions that depends on county be sure to accept it as parameter and don't pull the data from a global variable.
// helper_functions.js
// Bad
function someFunctionThatUsesCountry() {
console.log(country); // <- don't expect the global to be set
}
// Good
function someFunctionThatUsesCountry(country) {
console.log(country); // pull country ^ from the parameter list
}
You can then call you other script inside the IIFE by just passing the value.
(async () => {
// ...
someFunctionThatUsesCountry(country);
})();
If for some reason want a global variable really bad. You should place the promise inside this variable, not the value. With this promise you can pass the value, as well as notify other scripts when this value is available.
// script_1.js
window.country = fetch('https://extreme-ip-lookup.com/json/')
.then(response => response.json())
.then(ipData => ipData.countryCode);
// script_2.js (must be loaded after script_1.js)
window.country.then(country => { // <- wait until country is available
// do stuff with country
console.log(country);
});
Your problem come from the fact that your fetch is an asynchrone function, with a promise.
What you want to do is that (I suppose)
var country = '';
//then
fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
var cc = (response.countryCode);
country = cc;
});
//then
console.log(country);
But, since you use an async function, this is what is done:
//first
var country = '';
//second
fetch('https://extreme-ip-lookup.com/json/')
.then( res => res.json())
.then(response => {
//fourth
var cc = (response.countryCode);
country = cc;
});
//third
console.log(country);
How to fix that? it depend. If your console.log is triggered by a button, make it wait for country to be filled
else, put your code in the last then, or use Promise.all() (documentation here)
console.log is happening before fetch is resolved. Try this:
let country = '';
fetch('https://extreme-ip-lookup.com/json/')
.then(res => res.json())
.then(res => country = res.countryCode)
.then(() => console.log(country))
fetch returns a Promise, hence the .then() chain in your question.
But if you stepped into Promise Land, you won't find out. You'll have to do everything with Promises.
But you might split you logic into small manageable parts like here
console.clear()
let cached = null;
const lookup = () => fetch('https://extreme-ip-lookup.com/json/');
// Caching json and not the fetch promise, because
// https://stackoverflow.com/a/54731385/476951
const getJson = () => cached = cached || lookup() .then(response => response.json());
const getParameter = (parameter) => getJson() .then(json => json[parameter]);
const getCountry = () => getParameter('country') .then(value => value);
const getCountryCode = () => getParameter('countryCode') .then(value => value);
getCountryCode().then(countryCode => {
console.log('countryCode:', countryCode)
})
getCountry().then(country => {
console.log('country:', country)
})
getParameter('city').then(city => {
console.log('city:', city)
})

How to save firebase returned data to a variable

I am coding for my React Native app and I am having trouble getting the data from the firebase return outside of the firebase.firestore().collection("test_data").doc(ID) loop. Whenever I check the dataArray variable after the loop it is empty. If I check it within the loop, the data is there. I think that it is a scope problem, but I just do not understand it. I also cannot call any user defined functions inside of the loop.
try {
let dataArray = [];
// get the document using the user's uid
firebase.firestore().collection("users").doc(uid).get()
.then((userDoc) =>{
// if the document exists loop through the results
if (userDoc.exists) {
data = userDoc.data().saved_data; // an array store in firebase
data.forEach(ID => { // loop through array
firebase.firestore().collection("test_data").doc(ID).get()
.then((doc) => {
dataArray.push(doc.data().test_data);
console.log(dataArray) // the data shows
})
console.log(dataArray) // the data does not show
})
}
})
}
catch (error) {
}
}
You're looping through asynchronous calls, so your final console.log will trigger before the data has been received. Your first console.log only triggers after the data has been received.
So the code is working, but the function (promise) will resolve (as undefined, or void) before all the data has been received from your firebase calls.
If you want to return the array to the caller, you could do something like this:
function getDataFromServer() {
// get the document using the user's uid
return firebase.firestore().collection('users').doc(uid).get().then(userDoc => {
// now we're returning this promise
const dataArray = []; // can move this to lower scope
// if the document exists loop through the results
if (userDoc.exists) {
const savedData = userDoc.data().saved_data; // an array store in firebase
return Promise.all(
// wait for all the data to come in using Promise.all and map
savedData.map(ID => {
// this will create an array
return firebase.firestore().collection('test_data').doc(ID).get().then(doc => {
// each index in the array is a promise
dataArray.push(doc.data().test_data);
console.log(dataArray); // the data shows
});
})
).then(() => {
console.log(dataArray);
return dataArray; // now data array gets returned to the caller
});
}
return dataArray; // will always be the original empty array
});
}
Now the function returns the promise of an array, so you could do...
const dataArray = await getDataFromServer()
or
getDataArrayFromServer().then(dataArray => {...})

Push data into array's specific index after asynchronous request from server

I've an object and I push that into main array just when document is loaded, now after response from server data is pushed into specific arrays which are nested into main array.
I have tried making a new instance of MainData each time when I want to push into array, but object name has to be same (as there are lot of requests and all of them has to be asynchronous) that is why it is mixing up values.
I am doing right now:
// Knockout viewModel
function ViewModel() {
self = this
self.main_array = ko.observableArray([])
}
var pointer = new ViewModel();
ko.applyBidings(pointer);
// Constructor for dummy data
function MainData() {
self = this
self.id = ko.observable()
self.first_val = ko.observableArray()
self.second_val = ko.observableArray()
}
var main_data;
// Main function which is called when document is loaded
num_type = (data) => { // data is 1234
main_data = new MainData();
main_data["id"] = data;
pointer.main_array.push(main_data);
// Fetch Requests
fetch("Num/Func1").then(x => {
x.json().then(b => {
main_data.first_val(b);
char_type(b[0].char); // this has to be called once b is loaded
})
})
// Another fetch request which gives a little late response
fetch("Num/Func2").then(x => {
x.json().then(b => {
// It takes 10 plus seconds meanwhile char_type function has fetched data
main_data.second_val(b);
})
})
}
// char_type function
char_type = (data) => { // data is abc
main_data = new MainData();
main_data["id"] = data;
pointer.main_array.push(main_data);
// Fetch Request
fetch("Char/Func1").then(x => {
x.json().then(b => {
main_data.first_val(b); // This response comes before fetch to 'Num/Func2'
})
})
fetch("Char/Func2").then(x => {
x.json().then(b => {
main_data.second_val(b); // This response also comes before fetch to
//'Num/Func2'
})
})
}
The values from both indices mixed together i.e index that is having main_data.id = 123 carries data from index which is having main_data.id = abc
Also There are some server calls which are outside num_type and char_type function.
How to get rid of that mixing stuff?
You need to move the declaration of main_edata inside the function, so you get a different, local copy each time the function is called. Then, the fetch callbacks will close over the local copy related to the num_type/char_type call that triggered that specific fetch.
Change this:
var main_data;
// Main function which is called when document is loaded
num_type = (data) => { // data is 1234
main_data = new MainData();
// ...
}
to this:
// Main function which is called when document is loaded
num_type = (data) => { // data is 1234
var main_data = new MainData(); // <====== Note `var`
// ...
}
And add var before main_data in char_type, too.
You need to create local variable for each main function and then pass that to other functions.
like:
num_type = (data) => {
var main_data = new MainData();
other_fun(data,main_data)
}

Get value of return variable after subscribe()

I doing an Async call using the below code, I want to know the value of data that is generated inside the getData() function however, I am getting undefined because the call is not resolved yet. Is there any way to sort it out?
getData(address){
let url = 'https://maps.googleapis.com/maps/api/geocode/json?address='+address+'&key='+this.key;
let call = this.http.get(url).subscribe(data =>{
let data = data.json()
return data;
});
}
//this is undefined because it does not know if the call was finished or not
console.log(this.latlong)
secondMethod(item){
//this is also undefined
this.getData(item.address)
}
Well, here is what you can do to solve it, simply push the data inside an array, then you may retrieve it in other functions.
getData(address){
let array = [];
let url = 'https://maps.googleapis.com/maps/api/geocode/json? address='+address+'&key='+this.key;
let call = this.http.get(url).subscribe(data =>{
let data = data.json()
array.push(data);
});
return array;
}
secondMethod(item){
//now you'll be able to retrieve it !
this.getData(item.address)
}
getData(address){
let url = 'https://maps.googleapis.com/maps/api/geocode/json?address='+address+'&key='+this.key;
return this.http.get(url).map(data => data.json());
})
Then you need to subscribe to get a value.
secondMethod(item){
this.getData(item.address).subscribe(data => {
console.log(data);
});
}
Here's how you could make that work keeping in mind async.
getData(address, callback){
let url = 'https://maps.googleapis.com/maps/api/geocode/json?
address='+address+'&key='+this.key;
let call = this.http.get(url).subscribe(callback);
}
secondMethod(item){
this.getData(item.address, this.thirdMethod.bind(this))
}
thirdMethod(data) {
let data = data.json()
// do stuff
this.something = data['something'];
}

Categories

Resources