I have a web application that receives json from a server. I was using this code:
var http_request = new XMLHttpRequest();
var url = "url where I have the json"
http_request.onreadystatechange = handle_json;
http_request.open("GET", url, true);
http_request.send(null);
var obj;
function handle_json() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
var json_data = http_request.responseText;
obj = eval("(" + json_data + ")");
processData(obj);
} else {
alert("A problem ocurred");
}
http_request = null;
}
}
But now I want to receive json from two url's and show the information. How can I do this using JavaScript? I know eval is not the appropiate thing to do but this is just a prototype.
Thank you so much! :)
As others have mentioned, you simply need to make 2 requests. In order to re-use the code you have already written, you could define a function to get json that takes a url argument. Something like this:
function getJson(url, callback){
function handle_json() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
var json_data = http_request.responseText;
var parser = (JSON && typeof JSON.parse == 'function') ? JSON.parse : eval;
var obj = parser("(" + json_data + ")");
callback(obj);
} else {
alert("A problem ocurred");
}
http_request = null;
}
}
var http_request = new XMLHttpRequest();
http_request.onreadystatechange = handle_json;
http_request.open("GET", url, true);
http_request.send(null);
}
I replaced the call to eval with some logic that will call JSON.parse if it is present, otherwise it will use eval. Using this function would allow you to make multiple requests by calling it multiple times, like so:
getJson("some url", processData);
getJson("some other url", processData");
If you wanted to process data from different urls in different ways, just define another function similar to processData and pass it along instead, like getJson("some crazy url", processCrazyData);
Using a framework like jQuery would reduce the amount of code that you have to write, but this solution should get it done using basic javascript.
The easiest way would be to put it into a function.
function getJson(url) {
//Remove the var url="string" line
//Rest of code
}
function handleJson() {
//Other code
}
Alternatively, you could use jQuery, in which case your code would be:
$.getJSON('url goes in here',function(data){
processData(data);
});
And just use that whenever you want to grab a page.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
Good evening everyone. I know this will seem like an extremely easy subject for many here, but I've been struggling for a while to reconstruct a function I have in order to make it dynamic and reusable site-wide.
The main struggle I'm having is returning an Array using the following:
var arr = getData("admin/fullDatabaseAccess.php");
This doesn't return the array as expected. Now, without writing every possible variation of what I did to the getData function in an attempt to return the array which it creates, I'll first show you the original function which works:
function getData() {
var xmlhttp = new XMLHttpRequest();
var url = "admin/fullDatabaseAccess.php";
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
processResponse(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function processResponse(response) {
var arr = JSON.parse(response);
// do stuff with the array - I originally modified the DOM using jQuery here, however I now want to use this entire getData function as a more generically useful function
}
}
I would then trigger the getData function on the single page which I was using this code with to generate an array, followed by modifying the page elements with the array data.
THIS BRINGS ME TO MY PROBLEM - I tried to make this function re-usable across the site by creating this version below, and calling the array data using the code line I posted at first (var arr = ..):
function getData(file) {
var xmlhttp = new XMLHttpRequest();
var url = file;
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
processResponse(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function processResponse(response) {
var arr = JSON.parse(response);
return arr;
}
}
I cannot seem to feed the data back to the variable. I've tried restructuring the function quite a lot to return values within the nests etc but I've got to the point where I'm confusing myself and can't really show the examples I tried as I deleted them and decided to start again.
Any help would be greatly appreciated!!
You need to provide a callback to getData, like this
function getData(file, cb) {
var xmlhttp = new XMLHttpRequest();
var url = file;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
// Calls the callback function with the response data
cb(processResponse(xmlhttp.responseText));
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
function processResponse(response) {
var arr = JSON.parse(response);
return arr;
}
}
getData(file, function(data) {
// data is now what's being returned from processResponse()
});
I have created some little jt code, but it gives me error
function Mind(){
var request = "request";
var reply = "reply";
var words = '';
this.Reply = function(){
if(request == words.nouns[0].noun){
reply = words.nouns[0].noun;
}
else
reply = this.words.nouns[0].noun;
}
this.SetRequest = function(req){
request = req;
}
this.GetReply = function(){
return reply;
}
this.Parse = function(u){
var xmlhttp = new XMLHttpRequest();
var url = u;
var result;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
words = JSON.parse(xmlhttp.responseText);
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
return result;
}
this.Construct = function(){
words = this.Parse('mind/words.json');
}}
var mind = new Mind();
mind.Parse('mind/words.json');
and here is my json file
{
"nouns": [
{"noun": "child"},
{"noun": "father"}
]
}
In command live all goes well, but when I run this code, appears error
Uncaught TypeError: Cannot read property 'nouns' of undefined
Mutliple errors. The most fundamental one is that your code ignores that XMLHttpRequest is async, and wont return a value in the same way as "regular" functions. Read about it here: How to make a function wait until a callback has been called using node.js. The TL;DR is that you have to pass in a "callback-function" to your parse-method and "return" your value using that function, instead of using a return-statement. Google for "javascript callbacks" and read a few tutorials if this concept is new to you!
You also have some minor errors, like returning result from Parse, but never actually setting result to anything. Also words is being assigned in multiple places in a way that doesn't really make sense. But both of these things will go away when you solve the sync/async issues.
EDIT:
Essentially the fix looks like this:
this.Parse = function(u, callback){ // this "callback" is new
var xmlhttp = new XMLHttpRequest();
var url = u;
var result;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
words = JSON.parse(xmlhttp.responseText);
callback(null, words); // we're "returning" the words here
}
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
// no return statement here!
}
this.Construct = function(){
this.Parse('mind/words.json', function(error, words) {
// here you can use your words!
});
}}
I am trying to pass parameter1 and parameter2 into my update.inc.php, How can I combine them together and xmlsend() both of them. I only can pass one!
function insert(){
if (window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
}
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState == 4 && xmlhttp.status ==200){
document.getElementById('message').innerHTML = xmlhttp.responseText;
}
}
parameter1='bio='+document.getElementById('bio').value;
parameter2='good='+document.getElementById('good').value;
xmlhttp.open('POST','/condition_form/update.inc.php',true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.send(parameter1);
}//insert()
the send() method can take a param string, so you can just concatenate the 2 params using & like
xmlhttp.send(parameter1 + '&' + parameter2);
You can combine both parameter by using some delimitor like ; or # etc. and then while reading parameter use .split(delimitor) to seperate the parameters. See below code
xmlhttp.send(parameter1+'#'+parameter2);
And while reading
var parameter = //use method to get parameter
var paramArray = parameter.split('#');
I highly suggest to use http://api.jquery.com/jquery.post/ instead of writing old JS Ajax.
Still if you feel using the old system, you can do it by...
parameter1='bio='+document.getElementById('bio').value;
parameter2='good='+document.getElementById('good').value;
postdata = parameter1 + parameter2;
xmlhttp.send(postdata);
I am trying to figure out the best way to handle this scenario. Basically I want the flow to work like this:
1.) Get configuration data from server (async)
2.) Run doStuff() after configuration data is received (async)
3.) Run postResults after doStuff() completes
Currently I seem to have this flow working using PubSub.js, however I am trying to figure out how I can provide the results from config data (#1) to postResults (#3). While I seem to have the flow working with PubSub, I'm not sure how to access the configuration (#1) callback data from postResults (#3)
Here is a code summary:
PubSub.subscribe('config', doStuff());
fetchConfigurations();
function fetchConfigurations () {
var req = new XMLHttpRequest();
var url = CONFIGURATION_SERVER_URL;
req.onreadystatechange = function() {
if (req.readyState == 4 && req.status == 200) {
var configObject = eval('(' + req.responseText + ')');
PubSub.publish('config', configObject);
} else {
console.log("Requesting config from server: " + url);
}
}
req.open("GET", url, true);
req.send(null);
}
function doStuff() {
PubSub.subscribe('results', postResults);
var results = {};
// do some async work...
results['test1'] = "some message";
results['test2'] = "another message";
PubSub.publish('doStuff', results);
}
function postResults (doStuffId, doStuffData) {
var req = new XMLHttpRequest();
var url = TEST_RESULTS_URL; // I want to get this from the configObject is get in fetchConfigurations
req.open("POST",url,true);
req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
req.send(doStuffData['test1'] + doStuffData['test2']);
}
Using promise seemed like the a better fit for this problem instead of pub/sub, here is the implementation I ended up using:
https://github.com/hemanshubhojak/PromiseJS
I have 5 drop down lists which is dynamic in nature. But the only problem is all the option values are being fetched from mysql database and i really want the user to know that the query is happening at the backend and he should wait by displaying a gif or a line saying "loading.. " .
I've been looking all over for this and similar questions have been posted by others but i don't seem to get it working . Please help me out. Can somebody please give a easy solution?
Thanks.
I've placed an example here:
http://jsfiddle.net/cMEaM/embedded/result/
I've kept as much of the existing code the same so you should still recognise it. The getXMLHTTP function is the same:
function getXMLHTTP() {
//function to return the xml http object
var xmlhttp = false;
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
xmlhttp = false;
}
}
}
return xmlhttp;
}
There's a new sendGet function to handle the XHR request, which takes success and error callbacks.
function sendGet(url, onSuccess, onError) {
var req = getXMLHTTP();
var method = "GET";
if (req) {
req.onreadystatechange = function() {
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
onSuccess(req);
} else {
onError(req);
}
}
}
req.open(method, url, true);
req.send(data);
}
}
I borrow a throbber from Wikipedia to display when the data is loading.
var throbberHtml = "<img src='http://upload.wikimedia.org/wikipedia/en/2/29/Throbber-Loadinfo-292929-ffffff.gif'>";
And these are the new getXXX functions which replace the <select> with the throbber while the data is loading:
function getState(countryId) {
var div = document.getElementById('statediv');
var oldInnerHTML = div.innerHTML;
var onSuccess = function(req) {
div.innerHTML = req.responseText;
};
var onError = function(req) {
div.innerHTML = oldInnerHTML;
alert("There was a problem while using XMLHTTP:\n" + req.statusText);
};
div.innerHTML = throbberHtml;
sendGet("findState.php?country=" + countryId, onSuccess, onError);
}
function getCity(countryId, stateId) {
var div = document.getElementById('citydiv');
var oldInnerHTML = div.innerHTML;
var onSuccess = function(req) {
div.innerHTML = req.responseText;
};
var onError = function(req) {
div.innerHTML = oldInnerHTML;
alert("There was a problem while using XMLHTTP:\n" + req.statusText);
};
div.innerHTML = throbberHtml;
sendGet("findCity.php?country=" + countryId + "&state=" + stateId,
onSuccess, onError);
}
There are other improvements that could be made, but I tried to keep in the sprit of your existing code as much as possible.
E.g. you can see that most of code in the getXXX functions is the same, so you could refactor these to use mostly the same code. Also, using a JS framework such as jQuery will replace the XHR code with better, more cross-browser compatible code. It's usually always better to avoid reinventing the wheel when it comes to code!
And you may possibly decide that sending the HTML for a <select> tag is not the best data format for the XHR. You might go with JSON which would decouple your presentation from the data.