When I call function CallMe, I get a result from service but my HTML element has text undefined, because of service is still loading data. I try async, await on Test() but no results. I want this to be pure JS. What I do wrong?
CallMe(){
document.getElementById('testId').InnerHTML = Test();
}
function Test(){
var request = new XMLHttpRequest(); // Create a request variable and assign a new XMLHttpRequest object to it.
request.open('GET', 'https://some service'); // Open a new connection, using the GET request on the URL endpoint
request.send();
request.onload = async function () {
var data = await JSON.parse(this.response);
return data[0][0][0];
}
}
function CallMe() {
var request = new XMLHttpRequest(); // Create a request variable and assign a new XMLHttpRequest object to it.
request.open('GET', 'https://some service'); // Open a new connection, using the GET request on the URL endpoint
request.send();
request.onload = async function () {
var data = JSON.parse(this.response);
document.getElementById('testId').InnerHTML = data // depending on your response targert your desired property.
}
}
just do one method and when the call returns a response assign the value to your testId div
Rather than using XMLHttpRequest to make ajax call I recommend using fetch api as it uses Promises, which enables a simpler and cleaner API, avoiding callback hell and having to remember the complex API of XMLHttpRequest. (ref: https://developers.google.com/web/updates/2015/03/introduction-to-fetch).
Using fetch api the your code in pure js will look like below.
fetch('https://some service')
.then( res => res.json() )
.then(response => {
document.getElementById('testId').innerHTML = data[0][0][0];
})
.catch(error => console.error('Error:', error));
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 10 months ago.
I'm trying to access the NHL API for a personal project. I was getting CORS request errors and found the below solution to access all the different sites (some worked prior, and some didn't).
I'm passing through a link and based one the outputs it seems to be accessing the data on the page and displaying it in both JSON and string format. The only problem is I can't return any of that data out of the function as an object or otherwise.
Last 2 logs show undefined, and the 2 within the function output the data I want. Am I missing something obvious or is there a deeper issue with the website access?
Thanks.
function getJSON(url){
let request = new XMLHttpRequest();
request.open('GET', url);
request.onload = function () {
// Begin accessing JSON data here
let data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
//Start writing function here
console.log(data);
console.log(JSON.stringify(data));
let data2 = JSON.stringify(data)
return data2
} else {
console.log('error');
}
}
request.send();
}
let data1 = getJSON("https://statsapi.web.nhl.com/api/v1/people/8476459/stats?stats=statsSingleSeason&season=20212022")
console.log(data1);
console.log(JSON.stringify(data1));
You are doing asynchronous call, which means you return the value before the response even come back, that's why data1 is undefined
You can see this post for more information.
For your case, you can wrap the request with Promise
async function getJSON(url) {
return new Promise(function (resolve, reject) {
let request = new XMLHttpRequest();
request.open('GET', url);
request.onload = function () {
// Begin accessing JSON data here
let data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
//Start writing function here
let data2 = JSON.stringify(data)
return resolve(data);
} else {
return reject('error')
}
}
request.send();
}
)
}
async function main() {
let data1 = await getJSON("https://statsapi.web.nhl.com/api/v1/people/8476459/stats?stats=statsSingleSeason&season=20212022")
console.log(data1);
console.log(JSON.stringify(data1));
}
main();
A better way is to use Fetch API
async function getJSON(url) {
const data1 = await fetch(url).
then(response => response.json());
return data1;
}
async function main() {
const result = await getJSON('https://statsapi.web.nhl.com/api/v1/people/8476459/stats?stats=statsSingleSeason&season=20212022');
console.log(result);
}
main();
What is the correct way to call this API? The api url is: https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd
I tried with this code
<p id="demo">
</p>
<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
document.getElementById("demo").innerHTML = myObj.bitcoin;
}
};
xmlhttp.open("GET", "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd" + new Date().getTime(), true);
xmlhttp.send();
</script>
however the value I get is [object Object]. I want to get the value in "usd".
Where am I wrong? Thx
Replaces myObj with myObj.usd but returns null value
The API returns in the form of {"bitcoin":{"usd": -insert value here-}}, so you have to use myObj.bitcoin.usd
You need to access the usd part of the object when you set the innerHTML as #SuspenseFallback mentioned.
You also need to remove the + new Date().getTime() part from your URL string. I don't see a date part in the API docs for the price endpoint.
you should use the fetch method. the better and the modern way of calling API using native javascript.
There is no problem with the way you did it but there are a few things that you can do with fetch and not with XHR.
you can read more about fetch by this link: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
there is an example of using fetch:
fetch(
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd"
)
.then((response) => response.json())
.then((data) => {
console.log(data);
});
or you can use async-await to achieve the same result :
(async () => {
const response = await fetch(
"https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd"
);
const data = await response.json();
console.log(data);
})();
note: I have used Javascript Self Invoking Functions which is a
function that calls itself.
The answers quickly resolve the issue, however I ran into another problem where there are hyphenated words.
Sample API:
https://api.coingecko.com/api/v3/simple/price?ids=bitcoin-cash&vs_currencies=usd
I'm trying to make a pokedex for a school project, and am using JS for doing so. I found this api called pokeapi, and since it uses JSON, I thought of just getting the data in the page and returning a json of it, however when I try to use the method I created to do a request in a for loop, it doesn't seem to work, only working on the last element of the for loop:
let request = new XMLHttpRequest();
const getJSON = (link, action) => {
request.open("GET", link);
request.send();
request.onload = () => {
if (request.status === 200) {
let json = JSON.parse(request.response);
action(json);
} else {
console.log(`e:${request.status} ${request.statusText}`);
}
}
}
let counter = 1;
getJSON("https://pokeapi.co/api/v2/pokedex/1/", (json) => {
json.pokemon_entries.forEach((poke_entry) => {
getJSON(poke_entry.pokemon_species.url, (poke_sp) => {
console.log(poke_sp);
//console loggin poke_sp only shows one console log, the last member of `json.pokemon_entries`
})
});
});
This is because you have created a single XHR object.
Every time you make a request with it, you cancel the previous request.
Create a new XHR object (inside the getJSON function) for each request.
i.e. swap the order of
let request = new XMLHttpRequest();
and
const getJSON = (link, action) => {
Preface: I'm a novice at JS, have no formal training in it, and usually make things on the fly by researching what I am trying to do. That failed this time.
I am currently trying to make a short JS script that will serve as a bookmarklet. The intent is to leverage the Tinder API to show users of Tinder some of the profile pictures of users who liked them, normally available with the Gold Feature.
Currently, it looks like this:
var stringz;
var xhr = new XMLHttpRequest();
var tokez = localStorage.getItem("TinderWeb/APIToken");
var url = "https://api.gotinder.com/v2/fast-match/teasers?locale=en";
xhr.withCredentials = true;
xhr.open("GET", url);
xhr.setRequestHeader("accept", "application/json");
xhr.setRequestHeader("content-type", "application/json; charset=utf-8");
xhr.setRequestHeader("x-auth-token", tokez);
xhr.setRequestHeader("tinder-version", "2.35.0");
xhr.setRequestHeader("platform", "web");
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
stringz = xhr.responseText;
return stringz;
}
};
//Turn the xhr response into a JSON string
var jasonstring = JSON.parse(stringz);
//Grab the URLs
var jasonstrung = jasonstring.data.results.map(x => x.user.photos.map(y => y.url));
//Turn the URLs into a nicely formatted JSON string
var jason = JSON.stringify(jasonstrung, null, 4);
//See what we got
console.log(jason);
The reason I am doing both JSON.parse and JSON.stringify is that the returned data from the xhr is a text string formatted like JSON but it isn't actually JSON yet so I have to parse it in order to grab the pieces I want, then format them after so they aren't a goopy block (although the stringify part isn't super necessary)
On the first run of this in the Chrome Dev Console, it spits out the following:
VM5418:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse (<anonymous>)
at <anonymous>:18:24
My assumption as to why it does this is because stringz is not yet "filled up" and returns as "undefined" when JSON.parse tries to cut through it.
However, once the script completes, if one were to type console.log(stringz), the expected string appears! If one runs the entire script 2x, it prints out the final desired dataset:
[
[
"https://preview.gotinder.com/5ea6601a4a11120100e84f58/original_65b52a4a-e2b2-4fdb-a9e6-cb16cf4f91c6.jpeg"
],
[
"https://preview.gotinder.com/5a4735a12eced0716745c8f1/1080x1080_9b15a72b-10c3-47c6-8680-a9c1ff6bdbf7.jpg"
],
[
"https://preview.gotinder.com/5e8d4231370407010088281b/original_adb4a1e3-06c0-4984-bca1-978200a5a311.jpeg"
],
[
"https://preview.gotinder.com/5ea77de583887d0100f385b8/original_af32971d-6d80-4076-a0f8-92ab54f820b3.jpeg"
],
[
"https://preview.gotinder.com/5bf7a1a29c0764cc3409bb02/1080x1350_c9784773-b937-4564-8c96-1a380832fdab.jpg"
],
[
"https://preview.gotinder.com/5d147c0560364e16004bcf5e/original_bf550230-baba-4d70-8c75-da64a9ce1b6c.jpeg"
],
[
"https://preview.gotinder.com/5c9ca2c2c8a4501600a979aa/original_915f4c0f-eb58-4283-bc58-00fdadc3c33c.jpeg"
],
[
"https://preview.gotinder.com/541efb64f5d81ab67f4b599f/original_7f11dea4-41c8-4e9c-8c7a-0c886484a076.jpeg"
],
[
"https://preview.gotinder.com/5a8b56376c220c1f5d8b43d9/original_7c19a078-8bd7-48f9-8e30-123b8f937814.jpeg"
],
[
"https://preview.gotinder.com/5d0c18341ea6e416002bfb1d/original_41d203ce-d116-4714-a223-90ccfd928ff2.jpeg"
]
]
Is there any way to make this thing work in one go (bookmarklet style)? setTimeout doesn't work unfortunately, assuming it is a problem in terms of taking too long to fill "stringz" before I use JSON.parse on it.
Thank you!
The problem is coming from that XHR makes your function asynchronous: it sends a request and the response arrives later - during that time your next (and next, and next,....) lines of code are executed.
You have to start your JSON string transformation when the response has already arrived - that means you should place your code xhr.onreadystatechange (I had to comment out a lot of things so the snippet works):
var stringz;
var xhr = new XMLHttpRequest();
// var tokez = localStorage.getItem("TinderWeb/APIToken");
// var url = "https://api.gotinder.com/v2/fast-match/teasers?locale=en";
var url = "https://jsonplaceholder.typicode.com/posts";
// xhr.withCredentials = true;
xhr.open("GET", url);
// xhr.setRequestHeader("accept", "application/json");
// xhr.setRequestHeader("content-type", "application/json; charset=utf-8");
// xhr.setRequestHeader("x-auth-token", tokez);
// xhr.setRequestHeader("tinder-version", "2.35.0");
// xhr.setRequestHeader("platform", "web");
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// the response arrives here
stringz = this.responseText;
// start your JSON transformation when the
// response arrives
jsonTransform(stringz)
return stringz;
}
};
xhr.send();
// this part of code will be executed synchronously - this
// doesn't wait until your response arrives
var synchronous = 'this will be logged before response arrives'
console.log(synchronous)
function jsonTransform(stringz) {
//Turn the xhr response into a JSON string
var jasonstring = JSON.parse(stringz);
//Grab the URLs
// var jasonstrung = jasonstring.data.results.map(x => x.user.photos.map(y => y.url));
//Turn the URLs into a nicely formatted JSON string
// var jason = JSON.stringify(jasonstrung, null, 4);
//See what we got
const jason = JSON.stringify(jasonstring)
console.log(jason);
}
Another method
I suggest you use fetch() instead of xhr - with xhr you have to take care of everything - fetch() is quite new, with a Promise based syntax (you'll be meeting that a lot, if you work with APIs)
More on fetch():
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
const url = "https://jsonplaceholder.typicode.com/posts";
// fetch returns a Promise, so you can use
// .then, .catch, .finally - very handy!
fetch(url)
.then(resp => {
return resp.json()
})
.then(json => {
// you have the json formatted response here:
console.log(json)
})
.catch(err => {
console.log(err)
})
You could use fetch() with the friendly async-await syntax, that makes your code feel synchronous:
const url = "https://jsonplaceholder.typicode.com/posts";
// await can only be placed in an async function!
async function fetchAPI(url) {
// try-catch block to handle errors of the fetch()
try {
const response = await fetch(url)
const json = await response.json()
console.log(json)
} catch (err) {
console.log(err)
}
}
fetchAPI(url)
I have a PHP endpoint that returns a JSON-object (maybe that is not what this is?)
{"my_array":["a","b","c","d"]}
That's what you see when you view that page. It's created using
$array = [];
$array['my_array'] = ["a","b","c","d"];
echo json_encode($array);
When I use a regular XHR call from MDN
// get XHR from MDN
function getAjax(url, success) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
xhr.open('GET', url);
xhr.onreadystatechange = function() {
if (xhr.readyState>3 && xhr.status==200) success(xhr.responseText);
};
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send();
return xhr;
}
I can iterate over it using this post-call function:
getAjax('get-users.php', logOutput);
function logOutput(response) {
console.log(JSON.parse(response));
// returns: {"my_array":["a","b","c","d"]}
}
When I try to do this with fetch, it doesn't work.
fetch('get-users.php')
.then((res) => {
return res.json(); // also tried res.text();
})
.then((data) => {
console.log(data);
});
I'm not sure if the way I'm creating the output from PHP is wrong, or if my Fetch is wrong.
Here is an image of the code/console.log
Edit: I wanted to point out it's not a url/target problem, for the sake of site anonymity I whited out some parts of the link.