Return JSON from XMLHttpRequest Function - javascript

Hello I've been trying to wrap my head around returning data from a XMLHttpRequest Function. I've tried many different ways but the only thing i can get when i try to output the data to a console from out-side the function i always get 'undefined'. it only works if i do it from inside the function itself.
<script>
var object;
function loadJSON(path, success, error) {
var xhr = new XMLHttpRequest();
var obj1;
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
if (success)
success(JSON.parse(xhr.responseText));
//console.log(data); works here!
} else {
if (error)
error(xhr);
}
}
};
xhr.open("GET", path, true);
xhr.send();
}
object = loadJSON('jconfig.json',
function (data) { console.log(data); return($data);/*works here! but does not return!*/ },
function (xhr) { console.error(xhr); }
);
console.log(object);//does not work here
</script>
I know this is a very simple problem but I've been stuck with this problem for over an hour now and the answers given on other similar questions cant seem to get me over this obstacle. Any help is highly appreciated!
EDIT: I updated the code with some suggestions but i still cant get ti to work. Any suggestions to get the code above to finally return something i can use outside of the functions.

The line console.log(object) is executed just after the laodJSON() function is called and the JSON object isn't loaded till then.
This is related to callbacks and async functions. Your loadJSON() can only actually load the JSON when it get's response from the server.
Instead, if you want to call the JSON object outside the loadJSON() function, you need to use a callback function. Something like this:
<script>
var object;
function loadJSON(path, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
// Here the callback gets implemented
object = JSON.parse(xhr.responseText);
callback();
} else {
}
}
};
xhr.open("GET", path, true);
xhr.send();
return xhr.onreadystatechange();
}
loadJSON('jconfig.json', function printJSONObject(){
console.log(object);
});
// this will not work unless you get the response
console.log(object);
</script>
Update: "Returning" a value from an async function by the use of callbacks is pointless, since the next line of code will be executed immediately without waiting for the response.
Instead, if you want to use the object outside of the function sending an XHR request, implement everything inside your callback function.

Related

How to separate XMLHttpRequest from the main function for better visbility/testibility (without Promises / asnyc/await )

Imagine this function:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
doStuff(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}
This works fine, but it is impossible to test, and this function has become a monster.
So I'd like to refactor it, by separating all the different parts in their own unique functions.
The problem is, I do not know how to extract the XHR part and still keep it working.
I cannot use Promises nor asnyc/await and have to stick to using plain XHR.
What I'd normally do is to create a seperate async function for the ajax call (or the xhr in this case). Simply await it's result and go from there. Easy to separate. But I do not have the luxury of await or anything this time.
What I am trying to get at is something like this
function refactoredMyMainFunction() {
doSomeInitialStuff();
// more stuff..
let result = xhrFunction();
doStuff(result); // result would be undefined here, since I cannot wait for the xhr request to finish.
}
You can implement a callback-based API:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
xhrFunction(doStuff);
}
function xhrFunction(cb) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
cb(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}

How to call a callback method after HTTP request

My code is running inside a main function. One part of my code is to make an HTTP request with an parameter which was defined before in the function and than write the response in to a new variable and work with it later.
I would like to exclude these steps with HTTP Request outside of the main function, and just CALL the function and write the response in a variable.
Unfortunately I tried it, but it doesn't work.
Error: variable is undefined
My code:
function DoWork() {
//some code
var strResponseHttpRequest;
strResponseHttpRequest = HttpRequest(strInput, function(strInput) {
console.log(strInput);
};
//continue working with the variable 'strResponseHttpRequest'
//rest of my code
}
function HttpRequest(strInput, callBackMethod) {
var objRequest = new XMLHttpRequest(); //New request object
objRequest.onreadystatechange = function() {
// Waits for correct readyState && status
if (objRequest.readyState == 4 && objRequest.status == 200) callBackMethod(objRequest.responseText)
}
objRequest.open("get", "php/get-content.php?ID=" + strInput, true);
objRequest.send();
}
I hope you can help me to find out, where the issue is. If there are some better way to do this, let me know. I would be appreciate it. Thank you.
Do you mean an asynchronous callback? You'll want to wait until the server gives back the correct status and readyState.
Change this:
objRequest.onload = function() {
var strResponse = this.responseText;
return strResponse;
};
To this:
objRequest.onreadystatechange = function() {
// Waits for correct readyState && status
if (objRequest.readyState == 4 && objRequest.status == 200) callBackMethod(objRequest.responseText);
};`
and pass in a callback method as a second parameter to HttpRequest(strInput, callbackMethod) like so:
strResponseHttpRequest = HttpRequest(strInput, function(responseText) {
console.log(responseText);
});
Also add callbackMethod as a parameter like so:
HttpRequest(strInput, callbackMethod)
Where is your strInput variable in your DoWork() function coming from? Maybe you forgot to define it somewhere? Could be for example:
function DoWork(strInput) {
//some code
var strResponseHttpRequest;
strResponseHttpRequest = HttpRequest(strInput);
console.log(strResponseHttpRequest);
//continue working with the variable 'strResponseHttpRequest'
//rest of my code
}
function HttpRequest(strInput) {
function reqListener () {
console.log(this.responseText);
}
var objRequest = new XMLHttpRequest(); //New request object
objRequest.onload = function() {
var strResponse = this.responseText;
return strResponse;
};
objRequest.open("get", "php/get-content.php?ID=" + strInput, true);
objRequest.send();
}
DoWork("yourIDvalue");

Returning ajax data to different functions corresponding to different links

I'm at peak-frustration trying to resolve my mental block re: callbacks. I've read How to return value from an asynchronous callback function? and How to return the response from an Ajax call? (among many other posts), and indeed the latter was helpful with another problem. However what I'm trying to do now is just slightly different and I'm losing my mind trying to adapt it to my code. Maybe my approach is entirely wrong/fundamentally flawed (and not just immature, which I can live with)?
The essence of my problem is that rather than simply returning ajax result to a callback function, I need the resulting json to be available to different functions, corresponding to different events, i.e.:
linkOne.onclick = invoke ajaxReq + getJsonData, then call functionOne with getJsonData result as an argument
linkTwo.onclick = invoke ajaxReq + getJsonData, then call functionTwo with getJsonData result as an argument
linkThree.onclick = invoke ajaxReq + getJsonData, then call functionThree with getJsonData result as an argument
Can't this be done with the link.onclick definition? Why doesn't this work:
linkThree.onclick = functionOne(getJsonData);
Here's my code:
function ajaxReq() {
var request = new XMLHttpRequest();
return request;
}
function getJsonData() {
var request = ajaxReq();
request.open("GET", "/myJSON.json", true);
request.setRequestHeader("content-type", "application/json");
request.send(null);
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
var myJsonString = JSON.parse(request.responseText);
var myJsonArray = myJsonString["An Array in myJSON.json"];
// functionOne(myJsonArray); // callback: what if I need to pass this value to various functions?
return myJsonArray; // ... 'cause this ain't doin' it, and I don't know why
}
}
} // onreadystatechange
} // getJsonData
function functionOne(myJsonArray) {
var myJsonArray = getJsonData(); // why doesn't this work, since, in getJsonData, var request = ajaxReq(); returns an ajax request ?
}
And why, if var request = ajaxReq(); invokes ajaxReq function and returns its result to getJsonData, does var myJsonArray = getJsonData(); in functionOne not do the same?
Any help with this is much appreciated. (p.s. seeking a pure javascript fix, not jQuery.)
svs
As it has been answered in the links you have specified, that we cannot return value from asynchronous call to use it in a synchronous function call. So here is the trick -
Assign all the onclick listeners a common function.
link1.onclick = someCommonfunction;
link2.onclick = someCommonfunction;
link3.onclick = someCommonfunction;
And define the common function like following, which will have json data in the callback, and you can pass that data to any function call.
function someCommonfunction(e) {
/* this is the function which will be finally executed with json data after clicking */
var callback = function(jsonData) {
var myJsonArray = jsonData;
//do some condition check and call functionOne, functionTwo or functionThree
};
getJsonData(callback);
}
I modified getJsonData to call callback with the response data.
function getJsonData(callback) {
var request = ajaxReq();
request.open("GET", "/myJSON.json", true);
request.setRequestHeader("content-type", "application/json");
request.send(null);
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
var myJsonString = JSON.parse(request.responseText);
var myJsonArray = myJsonString["An Array in myJSON.json"];
callback(myJsonArray);
}
}
} // onreadystatechange
} // getJsonData

Vanilla Javascript Ajax call inside IIFE not responding

Hey guys I'm running an IIFE and an ajax call and it seems to not respond at all...
var $ = {
core:function(u){
return new $.httpRequest(u);
},
httpRequest:function(url){
var text;
var r = new XMLHttpRequest();
r.open("GET", url, true);
r.onreadystatechange = function () {
if (this.readyState != 4 || this.status != 200) return;
text = this.responseText;
};
r.send();
console.log(text);
return text;
}
};
Is there something silly I am missing? Just been over this a few times and I have my hands full and hope that our savvy SO members could help out. Should I place the return inside the onload?
The onreadystatechange function you assign is where you need to handle the responseText. You need to either process it there or call some function and pass it the data. Remember, the ajax call is asynchronous which means that you start it with your r.send(), your $.httpRequest() function finishes, your other javascript after it executes and then some time later the ajax call completes and calls your onreadystatechange function. At that point, all you can do is to either process the data right there in that function or call some other function and pass the data to it.
Here's one way of doing it using a callback function that you pass into your httpRequest function:
var $ = {
core:function(u){
return new $.httpRequest(u);
},
httpRequest:function(url, callback){
var r = new XMLHttpRequest();
r.open("GET", url, true);
r.onreadystatechange = function () {
if (r.readyState != 4 || r.status != 200) return;
callback(r.responseText);
};
r.send();
}
};
Example usage:
$.httpRequest("http://examplesite.com/myurl", function(data) {
// write code here to process the data
});

Getting undefined in javascript when calling ajax

function get_request(url) {
var request = new getXMLObject();
request.onreadystatechange = function () {
if (request.readyState == 4) {
alert(request.responseText);
var data = eval('(' + request.responseText + ')');
alert(data);
return data;
}
}
request.open("GET", url, true);
//alert(document.getElementById('energy').innerHTML);
request.send();
}
function loadjobs() {
var url = "loadjobs.php?tab=1&id=1111";
//var data=
//alert(check());
alert(get_request(url));
//alert(data);
}
When i m getting data in json format...i am gettin NULL in alert(get_request(url));
while i m getting in alert(data);
Help me
This is because the request in asynchronous . The get_request(url) function does to return anything and hence the null ( although I think it should be undefined and not null ) .
The onreadystatechange function gets called later in the time , when the AJAX request has been completed and the data is returned from the server and hence the alert there works .
This is a misunderstanding of how AJAX works. Ajax is asynchronous. The onreadystatechange function will be called after loadjobs(). The "return path" you are specifying can never work. get_request() will never be able to return the fetched value.
You have two options. Either make the script synchronous - this can be done but is not recommended because it can freeze the browser.
Or, better, handle everything you need to do inside the onreadystatechange callback.
Well, it's an asynchronous call. You will receive the data of request your after get_request has already returned. That means your request.onreadystatechange = function () will be executed long after alert(get_request(url)); is already finished. This means get_request will not be able to return any data from the AJAX call. That's what you have the request.onreadystatechange callback function for, to execute code at an undefined later time when you received the response.
The problem is that Ajax requests work asynchronously. So you can't return the data right away. The way you should do it is to specify a callback function which will handle the response data.
function handleJSON( data ) {
// ...
// do whatever you want to do with the data
}
ajax( "url/file.php?param=value", handleJSON );
////////////////////////////////////////////////////////////////////////////////
function getXmlHttpObject() {
var xmlHttp;
try {
xmlHttp = new XMLHttpRequest();
} catch (e) {
try {
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xmlHttp;
}
function ajax(url, onSuccess, onError) {
var xmlHttp = getXmlHttpObject();
xmlHttp.onreadystatechange = function () {
if (this.readyState == 4) {
// onError
if (this.status != 200) {
if (typeof onError == 'function') {
onError(this.responseText);
}
}
// onSuccess
else if (typeof onSuccess == 'function') {
onSuccess(this.responseText);
}
}
};
xmlHttp.open("GET", url, true);
xmlHttp.send(null);
return xmlHttp;
}​

Categories

Resources