I am trying to solve this problem of mine: I am making two ajax calls on window.load, and it seems like second AJAX response rewrite first one before I function can proceed it or I am making something wrong... anyway I am not able to solve it without making calls synchronous and i don't really want to do that for obvious reasons.
So Here is my code (Javascript) To Create new XMLHttpRequest:
function createRequest(){
if(window.XMLHttpRequest)
return new XMLHttpRequest;
else
return new ActiveXObject("Microsoft.XMLHTTP");
}
My send request function (to sending them)
function sendRequest( url, callback){
request = createRequest();
if(typeof callback === 'function'){
request.onreadystatechange = callback();
}
request.open("GET", url, true);
request.send();
}
and finally my callback
function handleData(){
return function(){
if (request.readyState == 4 && request.status == 200) {
serverResponse = JSON.parse(request.responseText);
switch(Object.keys(serverResponse)[0]){
case "a": function1(serverResponse.a,"a"); break;
case "b": function2(serverResponse.b,"b"); break;
}
}
}
I am creating my calls like this:
window.onload = function () {
sendRequest('url' , handleData);
sendRequest('url2', handleData);
}
NOTICE: As you can see, this is simplified version of my code.
In a switch I am calling function1 and 2 these functions are really handling JSON response from server. I am making calls on two different urls on a same domain with different json response.
Also when I make only one call it works well(Both of them)... Problem only occurs when I am trying to make 2 in a row - And when i make two calls only second one is processed right. Thats why i am thinking that second overwrite first.
I tried to make two functions to handleData so there was handleData1() and handleData2() instead of single handleData() with switch so i call them like this:
window.onload = function () {
sendRequest('url' , handleData1);
sendRequest('url2', handleData2);
}
but i run into problem where second ajax response(always the second call) but again only second one succeed. And then i put console.log(request) in both of em, and i get only JSON for second function trying to be processed with second function.(nothing about first one) Sometimes is second function called more times like 4.
Btw handleData2 does not depend on data from handleData1.
If any more questions please do ask :) Thanks
request = createRequest();
creates a global variable. Every call to the function will override that variable, which is what you are experiencing.
Create a local variable and pass the value to the callback:
var request = createRequest();
if(typeof callback === 'function'){
request.onreadystatechange = callback(request);
}
// ...
function handleData(request) {
// ...
}
Related
I have a site that makes an HTTP request for JSON data, then a callback function processes the data and displays it by creating a series of divs dynamically. What I want to do is to wait for that function to finish adding the divs to the page, then apply labels only to specific divs created by the previous code.
HTTP Request and Callback
function data(callback){
var url = //request url;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
document.body.className = 'ok';
//Parse returned string into an object, then pass the object to the callback function.
var data = JSON.parse(request.responseText);
callback(data);
} else {
document.body.className = 'error';
}
}
};
request.open("GET", url , true);
request.send(null);
}
function dataDisplay(data){
//outputs <div id="1064" class="displayed-data">
<p id="message1" class="hidden"></p>
}
data(dataDisplay);
The code above displays my data exactly how I want it to, but when I try to access the numbered ID of the divs I want to change, the function runs before the data is displayed on the page, causing a 'null' error because the data I am trying to change hasn't been added to the DOM yet.
Second Function to change original
function label(){
var message1 = document.createTextNode('//some label');
var displayedData = document.getElementById('1064').getElementById('message1');
displayedData.appendChild(message1);
document.getElementById('message1').classList.remove('hidden');
}
How do I get the second function to wait until the callback has completed before trying to access and change it? I tried a callback inside of a callback, something like: label(data(dataDisplay)); but it still threw the same errors, so I clearly did it wrong. Sorry, I am brand new to JavaScript and don't really know where to go from here.
Thanks for your help!
A pretty quick way of doing it correctly is with this inline function.
data(function(result) {
dataDisplay(result);
label();
});
Be aware that your data function itself completes very quickly - if you need something from its result, you will need to include it in its callback.
I know its a long question, so allow me to explain as best as I can.
I have two javascript functions that I want to run after the page loads, we will call them function1() and function2().
function1() uses AJAX to retrieve information from the database that will arrange the contents in a div from the information obtained in the database. It also returns the contents from the database once the function has finished.
function2() requires the value from the database in order to run properly, so it needs to wait until function1() returns its value before function2() runs. Unfortunately my code is not working, and without going into too much detail, below is a schematic of the code:
function function1() {
if (some_cookie_exists) {
//run some code
} else {
//send parameters through "POST"
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var a = some_value_from_database;
// change div content
return a;
}
}
//sending parameters
}
function function2(a) {
//run code that depends on value of "a"
}
window.onload = function() {
var data = function1();
function2(data);
The error I get is that var data is undefined. function1() retrieves the data successfully, and runs as I intended it to, but function2() does not execute at all, because the value is missing. Can anyone figure out why I am getting this and how I should go about solving this?
NOTE: I am really only familiar with Javascript (still novice at that), I know essentially nothing about JQuery, so if you do use this to fix the code, please explain to me why this works (it will save me trouble later)
AJAX is asynchronous (that's what the first A stands for). The results of the AJAX operation are not available in function1(), they're retrieved in the onreadystatechange handler that you attach to the XMLHttpRequest object. So it's not clear how you could be doing
var a = some_value_from_database;
in function1().
What you need to do is call function2() from the onreadystatechange handler.
If you post the actual implementation of function1 we may be able to provide more specific details.
UPDATE:
Here's how to call function2() when the value becomes available from the AJAX call:
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var a = some_value_from_database;
function2(a);
}
}
Do it with a callback.
function function1(callback) {
/* ... */
callback(data); // instead of return
}
var function2 = function(data) { // important: make "function2" a variable so that it can be passed as an argument later on
/* ... */
}
window.onload = function() {
function1(function2); // important: no parentheses after function2, otherwise it would be executed right away
}
Because ajax by definition is asynchronous, function2 will start executing before the ajax completes in function1. JQuery would be useful here, as you can place function2 in the success callback of the ajax call in function1.
So include JQuery in your HTML and the following JS should work:
$(function() { //same as onload
function1() ;
}
function function1() {
$.ajax({
url: "url here",
type: "GET",
success: function(data) { // data is what is returned in ajax response
// rearrange divs
function2(data);
}
});
);
function function2(data) {
}
More on the JQuery ajax function here:
http://api.jquery.com/jQuery.ajax/
I have three div elements, and I want to populate each element with its own content. I call the same AJAX (very generic) function each time, sending the name of the div id as a parameter:
//left-right rectangle content
var rl = getContent("rightLeft");
//bottom content
var br = getContent("bottomRectangle");
//top content
var rtr = getContent("rightTopRectangle");
If I do an alert(http.responseText) within the AJAX function, I get the correct html content from the remote page. (In fact, if I add an alert, it seems to "slow" the function down so that my content is returned properly each time I call it, but who wants alerts on their web page?).
But, without the alerts, the above calls will only properly process the last call. So, in the above sequence of calls, only the last div, where id="rightTopRectangle" will be filled with the html retrieved from the AJAX call. The previous two calls don't populate their divs with the AJAX retrieved html. If I shake up the order of the calls, it will always be the last AJAX call that works.
I get the feeling the problem has something to do with the asynchronous part, where the previous calls don't have enough time to process the request before the AJAX function is requested again and again.
Here's the AJAX function:
function getContent(element){
var url = "ajax/getcontent.php?cid="+element; //alert(url);
http.onreadystatechange=function(){
if (http.readyState==4 && http.status==200){ //alert(http.responseText);
var response = http.responseXML.documentElement;
callback(element,http.responseText);
}
}
http.open("GET",url,true);
http.send();
}
The function named "callback" (it works fine) looks like this:
function callback(e,c){
document.getElementById(e).innerHTML = "<div style=\"line-height:"+ document.getElementById(e).offsetHeight +"px;margin:0px auto 0px auto;text-align:center;\" >" + unescape(c) + "</div>";
}
UPDATE: This works now. I added one line to my getContent function:
function getContent(element){
var http = createRequestObject(); /*After Tej's answer, I took this line out
of the root of my script and placed it here, within the function, in order to
instantiate a new http object each time I call this function, so that they all
operate independently of one another*/
var url = "ajax/getcontent.php?cid="+element; //alert(url);
http.onreadystatechange=function(){
if (http.readyState==4 && http.status==200){
var response = http.responseXML.documentElement;
callback(element,http.responseText);
}
}
http.open("GET",url,true);
http.send();
}
You are re-using the same XmlHttpRequest for all of your ajax requests; this leads to the last request always winning because the others have been overwritten. You should instead create a new ajax request for each call.
http = CreateAjaxRequest();
http.onreadystatechange = function() { ... }
// etc
you should pass element parameter to your onreadystatechange function, try this,
req.onreadystatechange = function (el) {
return function() {
if (http.readyState==4 && http.status==200){ //alert(http.responseText);
var response = http.responseXML.documentElement;
callback(el,http.responseText);
}
};
}(element);
I have few functions, which calls another (integrated functions in browser), something like this:
function getItems () {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://another.server.tld/", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
items = $("a[href^=/courses/]", xhr.responseText);
}
};
xhr.send();
}
As I don't want to write more code inside and make each logical functionality separated, I need this function to return variable items.
I know there can happen some accidents (network/server is not available, has long-response...) and the function can return anything after gets data from the server or timeout occurs.
This seems be an async request. I don't think you will be able to return data from this function.
Instead, you can take a callback function as an argument to this function and call that callback when you have the response back.
Example:
function getItems (callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://another.server.tld/", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
};
xhr.send();
}
You're asking for synchronous requests: a function should not return until its return value can be computed even if this involves a hundred milliseconds of asking the server for the data.
By setting the third argument of xhr.open to true, you are using asynchronous requests — telling the browser that you want your function to return before the response from the server was received. Which pretty much means that it cannot return the items, since they have not been received yet.
Of course, using synchronous requests is an user interface pain, because your javascript is basically locked up until the response comes back a few hundred milliseconds later (if you're lucky).
What is advised is to correctly architecture your JavaScript code to account for asynchronous communications, and allow values to be returned through a callback instead of return. You don't have to, but it will save you a lot of pain in the end.
I'm fairly new to ajax but am trying to implement two simple calls to dynamically changes two separate divs on a page using javascript. I have no problems using one call at a time, but when I use two it seems like the second xmlhttprequest takes over the first and writes into both divs.
I've read and tried using the fixes listed on these two other posts both neither seem to work in my case:
Sending two Ajax requests to two different PHP scripts from single javascript function
Using two xmlhttprequest calls on a page
And here is my relevant code:
function request_handler(url, params, changed_div) {
if(window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
}catch(e) {
req = false;
}
}else if(window.ActiveXObject) {
try {
req = new ActiveXObject("Msxml2.XMLHTTP");
}catch(e) {
try {
req = new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
req = false;
}
}
}
if(req) {
req.onreadystatechange = function(){
if (req.readyState == 4 && req.status == 200){
document.getElementById(changed_div).innerHTML = req.responseText);
}
}
req.open("POST", url, true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(params)
return true;
}
return false;
}
Here is the basic format of each request using the function above:
request_handler("sample.php", parameters , "sample_div");
Apologies if I'm passing something simple up here, I just can't seem to get it to work.
This question
Using two xmlhttprequest calls on a page
does answer your question.
In your request_handler function, you're using a global variable req that gets overwritten every time you call that function.
If you change it to start:
function request_handler(url, params, changed_div) {
var req;
// Rest of your function
}
you should find that it works. In this case req has a local scope and so is not overwritten when you call request_handler for the second time.
Can I also suggest that you strongly consider using the likes of jQuery, Prototype or Dojo, if you're planning on writing Ajax scripts? Writing scripts that work cross-browsers is hard to do well and these frameworks do a lot of the legwork for you.
Your req is a global variable as it is defined without the var keyword, keep that in mind.
What I think happens is that the second call overwrites the first one. This is because of the (default) asynchronous nature of the XMLHTTPRequest. Your first function call will end, but the fetching of the page is still going. The second function call then overwrites the previous request.
This however does not explain why both div get filled with the result of the second call. I must say I'm a bit lost on that one.
This is a pretty common problem, especially if you don't want to take additional measures to block further calls until the first has finished loading. Its a bigger subject that I can cover in a post but there are several examples on the web of an "Ajax Queue" that effectively manages the order of requests received.
jQuery has a plugin for managing queues and I'm certain that most other JavaScript frameworks such as Prototype and MooTools will as well. If you're wanting to stick with raw JavaScript I would take a look at this web page:
http://www.cmarshall.net/MySoftware/ajax/index.html
He implements a queue very effectively and has an excellent example of its use.