Variable does not work outside of function - javascript

I have a function that loads a JSON file and gives it to a variable called articles. When i log articles inside of the function, it shows my json file, but when i log it outside of my function it doesn't show anything at all
I have tried to use let and var before articles inside of the function but that doesn't seem to work
var articles = ""
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status == 200 && xmlhttp.readyState == 4){
articles = xmlhttp.responseText;
console.log(articles);
}
};
console.log(articles);
console.log(xmlhttp);
xmlhttp.open("GET","articles.json",true);
xmlhttp.send();
I want to be able to call my json file outside of my function by using articles, so that i don't have ot type xml.responseText each time.

In short, JavaScript does not synchronously wait for I/O operations to finish (network call in this case).
What this means is that when you log articles "outside of the function", the articles variable has not yet been set (the http request has not been completed).
Why are you hoping to have access to articles globally?
You could optionally pass your articles into a processing method after the http request has responded like so:
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status == 200 && xmlhttp.readyState == 4){
var articles = xmlhttp.responseText;
processArticles(articles)
}
};
xmlhttp.open("GET","articles.json",true);
xmlhttp.send();
function processArticles(articles) {
// Do something with articles here
}

Related

Unable to get the same results with 2 pieces of somewhat similar XMLHttpRequest

Hope you are able to help or just help me understand why I have 2 almost similar codeblocks where one does not do what I expect.
I am trying to make some API calls where I populate a variable with the data that is pulled from the API call. In the first there is no problem at all, but the second I can't populate the variable.
I have tried googling the problem and it seems to be because of the asynchronous nature of XmlHttprequests. But again, I do not get why one solutions works and another don't.
The solution that work:
// Get JSON and convert it to an object
var obj;
const Http = new XMLHttpRequest();
const url = "https://type.fit/api/quotes";
Http.open("GET", url);
Http.send();
Http.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
obj = JSON.parse(Http.responseText);
}
};
In this solution I am able to get the data and populate the variable obj and use it globally.
link to the solution: https://codepen.io/Kfriis/pen/QWjGZmx
The solution that don't work:
//function that takes a currency in capital letters and returns
var rates;
var currency = 'gbp';
const currencyString = currency.toUpperCase();
const API = "api.frankfurter.app"
const URL = `https://${API}/latest?amount=1&from=${currencyString}&to=DKK`
const http = new XMLHttpRequest();
http.open("GET", URL);
http.send();
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
rates = JSON.parse(http.responseText);
}
};
console.log(rates)
This do, for some reason, not work. I do not get why the rates variable do not get populated since the request is basically the same for the first code snippet.
I have come down to an idea of it being because the data sent from the 2 API endpoints may be different in some way. Because if it was only because of the asynchronous requests, both code snippets should return undefined.
Link https://codepen.io/Kfriis/pen/VwvpKmd
I do hope someone is able to shine some light on this.
I must be doing something wrong in the second snippet, because I can console.log() from inside the onreadystatechange but not outside it. Which led me to believe for a long time that it was a scoping issue.
Your code does work. However, you're logging console.log(rates) outside the http.onreadystatechange-function which means you're logging the rates before you get the response. If you change the code block
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
rates = JSON.parse(http.responseText);
}
};
console.log(rates)
to
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
rates = JSON.parse(http.responseText);
console.log(rates)
}
};
it should work.
Here's a working example code if you wanna add the code to a function.
// Function that takes a currency in capital letters and returns
function getCurrencyRates(currency, cb) {
const currencyString = currency.toUpperCase();
const API = "api.frankfurter.app"
const URL = `https://${API}/latest?amount=1&from=${currencyString}&to=DKK`
const http = new XMLHttpRequest();
http.open("GET", URL);
http.send();
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
cb(JSON.parse(http.responseText));
}
};
}
// Call the function and pass "gbp" as currency.
// Rates will be logged in response.
getCurrencyRates('gbp', function(response) {
console.log(response);
});

Getting xmlhttp response empty when json object accessed through server path

I have a js function which goes to a spring controller class returning a json object with data like :
{"prop1":"val1",
"prop2":"val2"}
The js function is something like :
accessValue(a,b,c){
var xmlhttp = new XMLHttpRequest();
alert("This works 1");
xmlhttp.onreadystatechange = function() {
alert("This works 2");
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
alert("This works 3" + xmlhttp.status);//line 1
if (xmlhttp.status == 200) {
var jsonobj = JSON.parse(this.responseText); //line 1
alert("Hi ");
document.getElementById(b).innerHTML = jsonobj.prop1;
document.getElementById(c).innerHTML = jsonobj.prop2;
console.log(jsonobj.prop2);
}
else if (xmlhttp.status == 400) {
alert('There was an error 400');
}
}
};
xmlhttp.open("GET", a + "--spring controller class path --");
xmlhttp.send(null);
}
In the function parameters b and c are div ids which I want to update with the data which comes in the json object. Parameter a is a URL which is appended with spring path of the controller class, this class returns json object which runs perfectly fine.
At line 1, I am getting status for xmlhttp.status as 0 which is empty response. After searching online I found out that this may happen bcz the file may be accessed locally properly but through server its not happening. The same code when used on localhost works great. Is there a way I could access this spring controller returned json object on server using proper http url and parse the data to update my divs ?

accessing nested tags in XML files

I am making a simple XML parser in javascript using the XMLHttpRequest object, and i am having trouble returning only the tags I want. For example, for this xml file I would like to access and print the variant array (1st one), however my current code is not working.
JavaScript
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
function run() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://www.deadstock.ca/collections/adidas/products/adidas-equipment- support-adv-core-black-24.xml", true);
xhttp.send();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// Typical action to be performed when the document is ready:
console.log(xhttp.responseText.hash.variant[0]);
}
}
}
run();
However, this works (returns everything)
console.log(xhttp.responseText);
I am currently running the file using node.

Using a while loop to get rows using PhpExcel

I am looking to create javascript arrays with rows taken from an xlsx spread sheet using PHPExcel.
Here is my code
$document.ready({
var rows = new Array();
var vals = new Array();
var i = 0;
while(){
rows[i] = getRow(i);
vals[i] = getVal(i);
i++;
}
});
function getRow(i){
if(window.XMLHttpRequest){
xmlhttp= new XMLHttpRequest();
}else{
xmlhttp= new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
return xmlhttp.responseText;
}
}
xmlhttp.open('GET', 'data.inc.php?x='+i, true);
xmlhttp.send();
}
function getVal(i){
if(window.XMLHttpRequest){
xmlhttp= new XMLHttpRequest();
}else{
xmlhttp= new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
return xmlhttp.responseText;
}
}
xmlhttp.open('GET', 'include.inc.php?x='+i, true);
xmlhttp.send();
}
I am not sure what to check for in the parameter of the while loop (Im assuming we do not know how many rows are in the spreadsheet)
Is that my only issue or this the wrong way to go about it?
Also the function getRow return the entire row and getVal returns one column that will be important elsewhere on the page.
There are different approaches you can use:
1) Synchronise your requests:
function getRow(i, rows){
...
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
if xmlhttp.responseText != '' {
rows[i] = xmlhttp.responseText;
getRow(i+1, rows)
} else {
// call function that works with rows.
}
}
}
...
}
This function is only called with getRows(0, rows) (no loop!).
This is definitely the slowest approach because every request is started as soon as the previous request has finished.
2) Send number of rows first:
You could send the number of rows with the first or with each request, so javascript knows how many rows there are. Then you can loop over the rows and create asynchronous calls as you do now.
3) Send all rows at once:
I don't know your use case, but it looks like a waste of time to call every row separately. Why not make one call and return all of the data at once with linebreaks as delimiters (or something else suiting your data). If your data is really huge you could still break down the data into large chunks and combine this with option 1 or option 2.
4) Send data at page load:
Not sure if this is an option it looks like it is since you execute your function on document.ready. You could consider writing your data into a special hidden div and read the data from there (with javascript) into your variables. That way you avoid all the ajax calls. This is probably the fastest if you want to load all data anyway.
Note: you might consider using jQuery which makes working with ajax a lot easier. Check jQuery get for example.

Javascript error when reading large XML file

I am reading a large sitemap.xml file using the following code:
<div id="urls"></div>
<script type="text/javascript" language="javascript">
var xmlhttp;
if(window.XMLHttpRequest) xmlhttp = new XMLHttpRequest();else xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState==4 && xmlhttp.status==200) {
loc = xmlhttp.responseXML.documentElement.getElementsByTagName("loc");
for(i=0;i<loc.length;i++) {
document.getElementById("urls").appendChild(document.createTextNode( loc[i].firstChild.nodeValue ));
document.getElementById("urls").appendChild(document.createElement("br"));
}
document.getElementById("urls").innerHTML = table;
}
}
xmlhttp.open("GET", "sitemap.xml", true);
xmlhttp.send(null);
</script>
When reading an XML file with more than 1000 lines it will error with the following details:
Uncaught TypeError: Cannot read property 'documentElement' of null (index):xmlhttp.onreadystatechange
Any ideas on how I can get around this? Tried a few things which I have found online, but was unable to work it out properly.
Many thanks for your help.
You must check whether responseXML is null. That happens if the XML file the server returned has parsing errors.
var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function () {
var locs, i, urls = document.getElementById("urls");
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
if (this.responseXML) {
locs = this.responseXML.documentElement.getElementsByTagName("loc");
for (i = 0; i < locs.length; i++) {
urls.appendChild(document.createTextNode(locs[i].firstChild.nodeValue));
urls.appendChild(document.createElement("br"));
}
// What is that line? I've taken it from your code, but it can't be right.
urls.innerHTML = table;
} else {
// responseXML is null if the response has XML parsing errors
alert("The server did not send a proper sitemap file.");
}
}
};
xmlhttp.open("GET", "sitemap.xml");
xmlhttp.send();
Also, as shown above, you should really never use synchronous requests. The whole point of having an event-handing callback function like onreadystatechange is to be able to make asynchronous requests.
There also is a big red warning on the MDN about that: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest#onreadystatechange
Lessons to learn:
Never use objects without a prior check if they are valid.
Never use synchronous HTTP requests from JavaScript.

Categories

Resources