How to make a variable from json using XMLHttpRequest? - javascript

I would like to get an array with objects from json using XMLHttpRequest() and assign it to a variable.
If i log it in a console it shows the array.
function getData() {
let myJson = [];
var xhr = new XMLHttpRequest();
var url = 'https://www.reddit.com/r/funny.json';
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var jsonData = JSON.parse(xhr.responseText);
arr = jsonData.data.children;
for (let i = 0; i < arr.length; i++) {
let newObject = {};
newObject.title = arr[i].data.title;
newObject.upvotes = arr[i].data.ups;
newObject.score = arr[i].data.score;
newObject.num_comments = arr[i].data.num_comments;
newObject.created = arr[i].created_utc;
myJson.push(newObject);
}
}
};
xhr.open("GET", url, true);
xhr.send();
return myJson;
}
let data = getData();
console.log(data[0]);
But if I try to do anything with (console.log(data[0]);) it it returns undefined. What am I doing wrong? Thanks for any explanation! Cheers.

Just pass in the callback function instead of returning the value from an asynchronous XML HTTP request.
function getData(callback) {
var xhr = new XMLHttpRequest();
var url = 'https://www.reddit.com/r/funny.json';
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var jsonData = JSON.parse(xhr.responseText);
arr = jsonData.data.children;
let myJson = [];
for (let i = 0; i < arr.length; i++) {
let newObject = {};
newObject.title = arr[i].data.title;
newObject.upvotes = arr[i].data.ups;
newObject.score = arr[i].data.score;
newObject.num_comments = arr[i].data.num_comments;
newObject.created = arr[i].created_utc;
myJson.push(newObject);
}
// Invoke the callback now with your recieved JSON object
callback(myJson);
}
};
xhr.open("GET", url, true);
xhr.send();
}
getData(console.log);

Your return happens outside of the onreadystatechange. So you exit before you even have the data.

Pass in a callback function to call when you have the data, or have the asynchronous call return a JS Promise that resolves with the gotten data.

Related

Javascript GET request after POST request

I have a page that uses a function for getting some data, with a GET xhttp request, from a database (get_worktime_list()).
On the same page, I can add some data to the database with a form using a POST xhttp request and after a success (saved in the response) I will get the content included the new line from the database with the same function get_worktime_list().
The problem is that when getworktime is called after the POST request, get_worktime_list() makes another POST request instead of a GET. why???
function http_request(post_data, end_point, type)
{
console.log("HTTP");
var res = 0;
//var data = "data=0&username="+stored_token.username+"&token="+stored_token.token;
var data = "data=0&"+post_data;
console.log(data);
// Check if is valid token/username from database
const url = "http://192.168.1.188:5000/services/"+end_point;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(xhttp.responseText);
}
};
if (type == "GET")
{
console.log(url+"?"+post_data);
xhttp.open("GET", url+"?"+post_data, false);
}
else
{
console.log("Data: "+data);
xhttp.open("POST", url, false);
}
xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhttp.send(data);
xhttp.abort();
return res;
}
This add data to DB
function addworktime(username,token)
{
console.log("Aggiungo ore");
var date = document.getElementById("data").value;
var type = document.getElementById("turno").value;
var pay = document.getElementById("paga").value;
var emp = document.getElementById("dipendente").value;
var ore = document.getElementById("num_ore").value;
var data = "username="+username+"&token="+token+"&day="+date+"&turn_type="+type+"&pay="+pay+"&emp="+emp+"&ore="+ore;
var res = http_request(data,"admin/dipendenti/addtime.php","");
//console.log(res);
if (res.insert_ok == 1)
{
display_time_table(0,0,null);
} else {
console.log(res);
}
}
This function makes a GET request when a page load and a POST request when called by addworktime()
function display_time_table(from,to,cf)
{
let time_list_table = document.getElementById("list-container");
var time_list = get_worktime_list(saved_data.username,saved_data.token,from,to,cf);
let time_table = generate_time_list_table(time_list);
time_list_table.innerHTML = time_table;
}
function get_worktime_list(username,token,date_from,date_to,cf)
{
var data = "username="+username+"&token="+token;
if (cf != "" || cf != null)
{
data = data+ "&dipendente="+cf;
}
if (date_from != 0)
{
data = data +"&date_from="+date_from;
}
if (date_to != 0)
{
data = data + "&date_end="+date_to;
}
var time_list = http_request(data,"admin/dipendenti/getworktime.php", "GET");
return time_list;
}
The server can only accept GET requests for that API and obviously, I get a parse error parsing the JSON response.
Thanks for help

Protractor - How do I pass a string value from a previous function to an async script?

The issue I'm having is that I have a dynamic API call whose url changes everytime. So In order to get the proper URL I have to get the text on the page and parse it so it only the first part of the text, then concatenate that to the first part of the URL. When I try to pass the string to the async script it keeps coming up as undefined. How can I get the string into the async script?
Specifically get the string to this line of code:
xhr.open("GET", APIcall, true);
var ID = element(by.css(".sometext")).getText().then(function(getFirstPartOfText) {
//console.log(ID);
var thing = getFirstPartOfText
var thing2 = getFirstPartOfText.toString().split(" ");
var thing3 = thing2[0];
var API = "https://someAPIcall/read/";
APIcall = API + thing3;
return APIcall;
}).then(function(APIcall){
console.log(APIcall);
browser.executeAsyncScript(function(ApiCall) {
var callback = arguments[arguments.length - 1];
var xhr = new XMLHttpRequest();
xhr.open("GET", APIcall, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
};
xhr.send('');
}).then(function(str) {
console.log(str);
//var whatINeed = JSON.parse(str);
var ID = element(by.css(".sometext")).getText().then(function(getFirstPartOfText) {
// this is synchronous, so there's no need to chain it using .then()
var thing = getFirstPartOfText
var thing2 = getFirstPartOfText.toString().split(" ");
var thing3 = thing2[0];
var API = "https://someAPIcall/read/";
APIcall = API + thing3;
return APIcall;
});
call_something(ID); // ID should be set at this point.
function call_something (APIcall) {
console.log(APIcall);
browser.executeAsyncScript(function(ApiCall) {
var callback = arguments[arguments.length - 1];
var xhr = new XMLHttpRequest();
xhr.open("GET", APIcall, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
};
xhr.send('');
}).then(function(str) {
console.log(str);
}
}
There are multiple things going on here, first of all the callback in call_something is not required, you are still within webdriver's promise manager. So all you need to do is return the data for the next call chain. Also quote in xhr.send(''); inside the method are not required. All you need to do is call send() and JSON parse the response and return, the next then block should have the JSON result. If you are getting pure HTML, then make sure the URL is correct.
function call_something (APIcall) {
console.log(APIcall);
browser.executeAsyncScript(function(ApiCall) {
var xhr = new XMLHttpRequest();
xhr.open("GET", APIcall, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
return JSON.parse(xhr.responseText);
}
};
xhr.send();
}).then(function(str) {
console.log(str);
}
}
I was missing an extra parameter mentioned here
The first argument is a function which will be called
The second+ arguments will be passed as arguments to the function in the first argument.
var ID = element(by.css(".sometext")).getText().then(function(getFirstPartOfText) {
//console.log(ID);
var thing = getFirstPartOfText
var thing2 = getFirstPartOfText.toString().split(" ");
var thing3 = thing2[0];
var API = "https://someAPIcall/read/";
APIcall = API + thing3;
return APIcall;
}).then(function(APIcall){
console.log(APIcall);
browser.executeAsyncScript(function(ApiCall) {
var callback = arguments[arguments.length - 1];
var xhr = new XMLHttpRequest();
xhr.open("GET", APIcall, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
};
xhr.send('');
}, APIcall).then(function(str) {
console.log(str);
//var whatINeed = JSON.parse(str);

myObj.forEach(), isn't working

I'm trying store a XMLHttpRequest()'s results as a JSon String in an object, The data in the String is several arrays. I'm trying to then read through each array, in myObj.
Obviously, myObj.forEach() doesn't work, because myObj is an object, not an array or a list. How do I make it so I can itterate through myObj, and then use a forEach on each array?
Here is my current code
function getFile(){
var input = document.getElementsByName("json")[0];
var filename = input.value;
console.log(filename);
var xhr = new XMLHttpRequest();
xhr.open("GET", filename, true);
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var text = xhr.responseText;
document.getElementById("displayText").innerHTML = "";
var myObj = JSON.parse(text);
myObj.forEach(function(student) {...});
}
}
}
You can grab the keys of the Object into a list using Object.keys() and then iterate through them assuming they are all lists:
function getFile(){
var input = document.getElementsByName("json")[0];
var filename = input.value;
console.log(filename);
var xhr = new XMLHttpRequest();
xhr.open("GET", filename, true);
xhr.send(null);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var text = xhr.responseText;
document.getElementById("displayText").innerHTML = "";
var myObj = JSON.parse(text);
var keys = Object.keys(myObj);
keys.forEach(function(key) {
myObj[key].forEach(function(item) {...})
});
}
}
}

AJAX - How can I make certain all data is received? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
Background: I am attempting to retrieve data, using AJAX, and assign it to a variable. I have tried to set the AJAX request to synchronous, but Firefox will not allow it.
Question: How can I make certain all the data is received?
function search(){
var data = [];
this.init = function(){
data = getData({"url":"/imglib/Inventory/cache/2335/VehInv.js"});
console.log(data); // Returns as 'undefined'. Possibly because of asynchronous call?
};
var d = new Date();
function getData(url){
var xhttp: new XMLHttpRequest();
var dataURL = url + '?v=' String(d.getTime());
xhttp.onreadystatechange = function(){
if(this.readyState = 4 && this.status == 200){
var r = this.responseText;
var s = r.indexOf('[') + 1;
var e = r.indexOf(']');
var jsonData = JSON.parse("[" + r.slice(s,e) + "]");
return jsonData;
}
};
xhttp.open("GET", dataURL, true);
xhttp.send();
}
};
you have to use a callback when working with asynchronous stuff..
function search(){
this.init = function(){
getData("http://www.petesrvvt.com/imglib/Inventory/cache/2335/VehInv.js", function(data){
console.log(data); // Returns as 'undefined'. Possibly because of asynchronous call?
});
};
var d = new Date();
function getData(url, callback){
var xhttp: new XMLHttpRequest();
var dataURL = url + '?v=' String(d.getTime());
xhttp.onreadystatechange = function(){
if(this.readyState = 4 && this.status == 200){
var r = this.responseText;
var s = r.indexOf('[') + 1;
var e = r.indexOf(']');
var jsonData = JSON.parse("[" + r.slice(s,e) + "]");
callback(jsonData);
}
};
xhttp.open("GET", dataURL, true);
xhttp.send();
}
};
Call the function that will deal with the data from the function invoked on "onreadystatechange". The reason it doesn't work is that the variable "data" isn't defined with the result of the async query when you are attempting to use it.
(function search() {
var data = [];
this.init = function() {
data = getData({
"url": "http://www.petesrvvt.com/imglib/Inventory/cache/2335/VehInv.js"
});
// This is definitely caused by the asynchronous XMLHttpRequest
//console.log(data); // This needs to be moved to the callback that is invoked when the request completes. See below
};
var d = new Date();
function getData(url) {
var xhttp: new XMLHttpRequest();
var dataURL = url + '?v='
String(d.getTime());
xhttp.onreadystatechange = function() {
if (this.readyState = 4 && this.status == 200) {
var r = this.responseText;
var s = r.indexOf('[') + 1;
var e = r.indexOf(']');
var jsonData = JSON.parse("[" + r.slice(s, e) + "]");
// This is how you be sure you get your data
console.log(jsonData);
}
};
xhttp.open("GET", dataURL, true);
xhttp.send();
}
})();

Calling data from JSON file using AJAX

I am trying to load some data from my JSON file using AJAX. The file is called external-file.json. Here is the code, it includes other parts that haven't got to do with the data loading.The part I'm not sure of begins in the getViaAjax funtion. I can't seem to find my error.
function flip(){
if(vlib_front.style.transform){
el.children[1].style.transform = "";
el.children[0].style.transform = "";
} else {
el.children[1].style.transform = "perspective(600px) rotateY(-180deg)";
el.children[0].style.transform = "perspective(600px) rotateY(0deg)";
}
}
var vlib_front = document.getElementById('front');
var el = document.getElementById('flip3D');
el.addEventListener('click', flip);
var word = null; var explanation = null;
var i=0;
function updateDiv(id, content) {
document.getElementById(id).innerHTML = content;
document.getElementById(id).innerHTML = content;
}
updateDiv('the-h',word[i]);
updateDiv('the-p',explanation[i])
function counter (index, step){
if (word[index+step] !== undefined) {
index+=step;
i=index;
updateDiv('the-h',word[index]);
updateDiv('the-p',explanation[index]);
}
}
var decos = document.getElementById('deco');
decos.addEventListener('click', function() {
counter(i,-1);
}, false);
var incos = document.getElementById('inco');
incos.addEventListener('click', function() {
counter(i,+1);
}, false);
function getViaAjax("external-file.json", callback) { // url being the url to external File holding the json
var r = new XMLHttpRequest();
r.open("GET", "external-file.json", true);
r.onload = function() {
if(this.status < 400 && this.status > 199) {
if(typeof callback === "function")
callback(JSON.parse(this.response));
} else {
console.log("err");// server reached but gave shitty status code}
};
}
r.onerror = function(err) {console.log("error Ajax.get "+url);console.log(err);}
r.send();
}
function yourLoadingFunction(jsonData) {
word = jsonData.words;
explanation = jsonData.explanation;
updateDiv('the-h',word[i]);
updateDiv('the-p',explanation[i])
// then call whatever it is to trigger the update within the page
}
getViaAjax("external-file.json", yourLoadingFunction)
As #light said, this:
function getViaAjax("external-file.json", callback) { // url being the url to external File holding the json
var r = new XMLHttpRequest();
r.open("GET", "external-file.json", true);
Should be:
function getViaAjax(url, callback) { // url being the url to external File holding the json
var r = new XMLHttpRequest();
r.open("GET", url, true);
I built up a quick sample that I can share that might help you isolate your issue. Stand this up in a local http-server of your choice and you should see JSON.parse(xhr.response) return a javascript array containing two objects.
There are two files
data.json
index.html
data.json
[{
"id":1,
"value":"foo"
},
{
"id":2,
"value":"bar"
}]
index.html
<html>
<head>
</head>
<body onload="so.getJsonStuffs()">
<h1>so.json-with-ajax</h1>
<script type="application/javascript">
var so = (function(){
function loadData(data){
var list = document.createElement("ul");
list.id = "data-list";
data.forEach(function(element){
var item = document.createElement("li");
var content = document.createTextNode(JSON.stringify(element));
item.appendChild(content);
list.appendChild(item);
});
document.body.appendChild(list);
}
var load = function()
{
console.log("Initializing xhr");
var xhr = new XMLHttpRequest();
xhr.onload = function(e){
console.log("response has returned");
if(xhr.status > 200
&& xhr.status < 400) {
var payload = JSON.parse(xhr.response);
console.log(payload);
loadData(payload);
}
}
var uri = "data.json";
console.log("opening resource request");
xhr.open("GET", uri, true);
xhr.send();
}
return {
getJsonStuffs : load
}
})();
</script>
</body>
</html>
Running will log two Javascript objects to the Dev Tools console as well as add a ul to the DOM containing a list item for every object inside the data.json array

Categories