AJAX call with common parameters gives always readyState = 1 - javascript

I'm writing a ColdFusion application that fills with some HTML content some divs once the corresponding button is clicked.
What happens is that the readyState never goes up from the initial state of 1.
The fact that makes me crazy is that I used the same AJAX code in other modules that work fine.
I tried manually the code in my applet "___AJAX_load_translator.cfm" to see if works correctly (inputting a complete url with parameters and query string) and it works.
I put many alerts in these javascript functions to trace if the url was created correctly, the parameters were formatted correctly and so on. Everything seems fine. This is driving me crazy. The result is the same on FireFox and IE.
function getHTTPObject(){
if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP");
else
if (window.XMLHttpRequest) return new XMLHttpRequest();
else {
alert("No AJAX support.");
return null;
}
}
function setOutput(divID){
if(httpObject.readyState == 4 && httpObject.status == 200){
document.getElementById(divID).innerHTML = httpObject.responseText;
} // else alert(httpObject.readyState + ' ' + httpObject.status);
}
function loadeditor(divID,CP,PP){
<CFOUTPUT>var CF_TOKENS = "CFID=#CFID#&CFTOKEN=#CFTOKEN#";</CFOUTPUT>
var operativeurl= "___AJAX_load_translator.cfm?"+CF_TOKENS+"&CP="+CP+"&PP="+PP;
httpObject = getHTTPObject();
if (httpObject != null) {
httpObject.open("POST", operativeurl, true);
httpObject.onreadystatechange = setOutput(divID);
httpObject.send(null);
}
}
I noticed that, putting an alert into the setOutput function, it displays a sudden readystate of 1. Then the browser statusbar shows the status of wait for a call to the server, that disappears quite immediately. It seems that the call is really done in that moment, and probably it is imho.
But it seems to me that after that readyness of the call (state 1) there is no more proceeding. It seems somehow blocked. Or, the function setOutput is deactivated. Maybe a second change to a state of 4 happens and this state is not registered by the callback ? In this case, why the DIV is not updated with the new content ?
Thanks for any help.

httpObject.onreadystatechange = setOutput(divID);
^^^^^^^
You're calling/executing your setouput function right then and there, and whatever the function returns becomes on the onreadystatechange callback "pointer".
Remove the (divID) portion, so you assign the function itself, not whatever it returns:
httpObject.onreadystatechange = setOutput;

Related

Why a code continues when the function doesnt return value yet. (in xmlhttprequest, calling php file.) Is it related to Sync/Async functions?

Came here again with lame questions as I am in process of learning/coding.
I would like to change a property of a disable value on button: During function performing its job, button should be disabled, once function finishes and return the values, button should be enabled again.
In function which creates a buttons I am calling update() function which loading php file via XMLHttpRequest. Then running the php code and return values on page. I want to have button disabled during this time. But everytime I call the function the button will not change. Or if changed it was so fast that I didnt even saw it.
here is a code:
global_button = document.createElement("button");
// let btn1 = document.createElement("button");
global_button.innerHTML = "UPDATE";
global_button.id = "update";
global_button.disabled = false;
document.body.appendChild(global_button);
document.getElementsByClassName("two")[0].append(global_button);
global_button.addEventListener("click", function () {
console.log("After CLICKED");
global_button.disabled = true;
update();
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
update function:
var xmlhttp;
function loadFile(file, func){
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = func;
xmlhttp.open("GET", file, true);
xmlhttp.send();
}
function update(){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
}
When I checked the console, it shows both console logs immediately: "After CLICKED" and "AFTER FUNCTION RETURN VALUES" messages. And couples seconds later, result of the function appear. But button wont change whatsoever.
I am suspecting the sync/async functions ? I read something for the .open method and vale true/false, but nothing changed if I switched from true to false. Also thinking if I should put it on the loop or something which will check the button clicked ? But I thought that listener would do the job.
Can anybody check and give me an advice ? or correct my thinking if it's wrong?
many thanks all of you. :)
The problem is indeed due to the asynchronous nature of the send method of XMLHttpRequest - and therefore of your update, which calls it.
When you call update(), which itself calls this:
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
all that happens is that you set up an XMLHttpRequest object and use its send method to send a request, telling it to call this function:
function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
}
});
as a "callback" when the readyState changes. (And in particular, when the request is complete and a response received.) But calling update does not wait for that state change to happen and block your code from running - hence the next lines of code, which set the disabled state of the button to false and log to the console - are executed straight away. So the button gets disabled but then instantly un-disabled, and therefore you never see it disabled. (In fact the browser will never even "paint" the screen with a disabled button, since it doesn't get a chance to do this while your code is running, so even if you could in theory do a freeze-frame here you would never see a disabled button.)
To fix it, you have to work with the asynchronous code you're using. Anything you want to happen after the state change has to take place in the callback function you pass it. So you can simply fix your problem by changing the update definition to this:
function update(){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
}
});
}
and delete those two lines of code from the place you've currently got them, after the update call.
Although note that this will only work if global_button is in scope inside update, which it might not be depending on how your code is structured (it probably shouldn't be to be honest). And even if it does, it's not good to hardcode your update to always undisable the button afterwards, with no guarantee the button will even be disabled first.
It's therefore better to define update to itself take a callback function:
function update(callback){
loadFile("update.php", function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById("content").innerHTML = xmlhttp.responseText;
callback();
}
});
}
and then call it like this in your main code:
global_button.disabled = true;
update(function() {
global_button.disabled = false;
console.log("AFTER FUNCTION RETURN VALUES");
});
because this separates the concerns of update itself ("make this request and set the content inner HTML to the response"), from whatever you might want to do afterwards, which could be different each time.
Finally, I can't not mention that this callback-based asynchronous code is very old-fashioned now. XMLHTTPRequest itself is quite a cumbersome API. I highly recommend you look into its modern equivalent, fetch, which is based on Promises - which while not without their mental gotchas are a much more understandable way to write asynchronous code. In particular with async and await you can write code that looks much like what you originally had: putting await update(); would actually do what you are waiting, and have the rest of your code wait for update to complete. But you can't just make that change to your original code because that only works if update returns a Promise, which in turns would mean completely rewriting your loadFile to use a more modern, Promise-based approach.

Callback in javascript ajax request

I have a function to handle an ajax request, with a callback.
What this code does is that it sends a request, and writes the response inside a div in my html page.
However i encounter problems with the callback, and i am not sure if the function works properly...
So my question is about the 2 lines of code inside xmlhttp.onreadystatechange and i have highlighted them.
Code:
function check_if_over(callback) {
//first i collect some variables from the UI
var val1 = $('#timer').text(),
val2 = $('#work').val();
var val5=val1.split(":",1);
//I initialize the xmlhttp object
xmlhttp=GetXmlHttpObject();
if (xmlhttp==null)
{
alert ("Your browser does not support Ajax HTTP");
return;
}
xmlhttp.onreadystatechange = function() {
//*****my question is about this part inside the "if"
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
document.getElementById('content0').innerHTML=xmlhttp.responseText;
callback.call(xmlhttp.responseText);
}
};
xmlhttp.open('GET','Controller?action=check&timer='+val5+'&work='+val2);
xmlhttp.send();
}
So my question is, if the xmlhttp.onreadystatechange works properly like that, performing the task of (a) writing the appropriate code inside my div, and (b) performing the callback.
Thanks!
EDIT:
So after that i do this thing, and i see that it does my prints in a non-expected way, as it skips the first print on the first iteration of this code, and makes it exactly on the time for the second iteration like that:
point 2
point 2
(small wait)
point 1
(I am basically alternating between 2 states every 1 minute, so i use this to check asynchronously something in the server-side. So this is where the checking happens.)
check_if_over(function() {
alert("point 1");
over = document.getElementById("value_ok").firstChild.nodeValue;
}
alert("point 2");
EDIT 2:
It seems that with jquery it works perfectly,
point 2
(small wait)
point 1
point 2
(small wait)
etc..
If you're already using jQuery why not use jQuery's $.get function?
function check_if_over(callback) {
//first i collect some variables from the UI
var val1 = $('#timer').text(),
val2 = $('#work').val(),
val5 = val1.split(":",1);
$.get('Controller?action=check&timer='+val5+'&work='+val2, function(data) {
$('#content0').html(data);
callback.call(data);
});
}

getElementById() null error

For those who wants the soluce before the question :
1 ) Don't read an element with getElementById() before it's really created : see windows.onload.
2 ) If you are using XMLHTTPRequest and AJAX stuff, call you're getElementById() , or unlock this function, in the callback ,(xhr_object.readyState == 4 part of your request).
In my case, i call my page without using the desired callback (noobish Ctrl-C Ctrl-V style).
Here was the question :
I'm facing a strange case in a HTML/Javascript code.
The aim of this code is to get the value of an HTML input (type text) via a JS function.
The context is that a main HTML page loads my all my JS functions, and loads on demand HTML contents in sub divs via HTTPRequest.
The selected code is called after the divs has been loaded.
Here's the PHP generated Input field that i have to read:
<input id="listejf" type="text" value="6|7|">
Here's my JavaScript call :
listejf=document.getElementById('listejf').value;
alert(listejf);
This code doesn't work. Firebug sends me:
TypeError: document.getElementById("listejf") is null
The strange thing is that I can make it work if I call the getElementById through an alert like this:
alert(document.getElementById("listejf"));
listejf=document.getElementById('listejf').value;
alert(listejf);
The first alert displays null, but the second one "6|7|", as expected.
Now, 2 questions:
Why does alert make it work ?
How can I make it work without throwing alerts everywhere?
Re-edit, the code was gone :
That's is the main HTML page : main.html
<head>
<script type="application/javascript" src="./preload.js"></script>
</head>
<body>
Link
<div id="targetid"></div>
</body>
preload.js looks like that :
function CallPagen() {
envoieRequete('./PageN.php', 'targetid');
}
function mytestfunction() {
listejf = document.getElementById('listejf').value;
alert(listejf);
}
function envoieRequete(url, id) {
var xhr_object = null;
if (window.XMLHttpRequest) xhr_object = new XMLHttpRequest();
else if (window.ActiveXObject) xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
xhr_object.open("GET", url, true);
xhr_object.onreadystatechange = function () {
if (xhr_object.readyState == 4) {
if (!document.getElementById(id)) {
alert("id pas trouvé " + id);
}
document.getElementById(id).innerHTML = xhr_object.responseText;
mytestfunction();
}
};
xhr_object.send(null);
}
PageN.php just echoes the inputtext field with the value filled.
"...I can make it work if i call the getelement through an alert like this..."
This almost always means that you're making an asynchronous AJAX request.
"Why does alert make it work ?"
What happens is that the alert delays the processing of the next line of code long enough for the response to return.
Without the alert, the next line of code runs immediately, and the element is not yet available.
"How can I make it work without throwing alerts everywhere?"
This is a very common issue. The solution is that you need to put any code that relies on the response of the XMLHttpRequest request inside a callback to the request.
So if you're making a request through the native API, you'd add a onreadystatechange callback...
xhrRequest.onreadystatechange = function() {
if (xhrRequest.readyState === 4) {
// append the response text to the DOM
listejf=document.getElementById('listejf').value;
alert(listejf);
}
}
You should run the code after DOM is ready, when the alert() is called, document is loading and browser has time for creating the DOM objects, try the following:
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading.
window.onload = function() {
var listejf = document.getElementById('listejf').value;
alert(listejf);
};

AJAX / ASP - Simple Task But I'm stuck?

I'm trying to do a simple AJAX call to an ASP page, that resets session variables and posts a little message back on completion. I'm doing this purely to learn AJAX.
The example came from W3 Schools website but since applying it to my page, I can't seem to get it to work and it's not producing any errors, which is annoying, because I can't debug it.
This is my JS, which is called when a user hits a button [Clear Form]:
function resetSearchForm()
{
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp=new XMLHttpRequest();
}
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("notification").innerHTML=xmlhttp.responseText;
document.getElementById('notification').style.visibility = 'visible';
}
}
xmlhttp.open("GET","clearSearchData.asp",true);
xmlhttp.send();
document.searchFrm.searchStr.value='';
document.searchFrm.vertical.checked = true;
document.searchFrm.horizontal.checked = true;
document.getElementById('dateRange').selectedIndex = 0;
document.searchFrm.searchStr.focus();
}
And this is the ASP (clearSearchData.asp) that clears my session variables and writes a message:
Response.Expires = -1
Session("search-str-boolean") = ""
Session("search-str-plain") = ""
Session("date-range") = ""
Session("date-from") = ""
Session("date-to") = ""
Session("specificDate") = ""
Session("peopleStr") = ""
Session("orientation") = ""
Response.Write "Form has been reset"
Can anybody see where I'm going wrong? I have been looking at it for a long time and I just can't see it.
The function itself works because the last part of the function gets processed, the bit that clears the form values... but... the AJAX call doesn't happen because the session variables still contain data and the message doesn't appear.
Many thanks in advance...
UPDATE - - - - - - - - - - -
It now works. The problem was I didn't include the full URL to the ASP page. Thanks for 'thedaian' (below) for pointing that out
Chances are, something is wrong with the page you're trying to get via AJAX. Check what xmlhttp.status is, if it's 404, then you're never going to get to the point where you're printing the AJAX response. Make sure that "clearSearchData.asp" is accessible from the same directory as your javascript. This is a common problem if you have your javascript code in a separate folder from the rest of your site. Or simply put in the full URL path for the "clearSearchData.asp" so it'll definitely work.
Something to point out, the function in xmlhttp.onreadystatechange is (usually) called after it's declared in the code. In this case, it gets called after your search form fields are cleared out and reset.
The ajax call does not automatically send along a session cookie. That means the session you're clearing is not the user's session, but just a session that's been created for that ajax call alone.

onreadystatechange in a loop, readystate changes too late

I issue in a loop a total of eight xmlhttprequests to a Google map server and process the json objects the server returns to retrieve the zip codes. The code works fine if the xmlhttprequests are synchronous. Since I'm supposed to use asynchronous requests, I'm trying to convert the code to asynchronous. It doesn't work.
I use two alerts to monitor myZip. When the code is run, the second alert, right above the return, runs eight times and shows myZip as null or undefined and that is what is returned. Then the first alert runs eight times and gives the desired zip code, too late, unfortunately. It seems to me the readystate doesn't change until too late.
How should I modify the code so it will return the zip code, not null? Any help will be greatly appreciated.
var url = "http://maps.googleapis.com/maps/api/geocode/json?address="+address+city+state+"&sensor=false";
req.open("GET", url,true);
var myZip;
req.onreadystatechange = function()
{
if(req.readyState == 4 && req.status == 200) {
(function(data){
var myObj = eval( '(' + data + ')' );
if(myObj.status=="OK"){
for(i=0; i <myObj.results[0].address_components.length; i++){
if(myObj.results[0].address_components[i].types=="postal_code"){
myZip=myObj.results[0].address_components[i].long_name;
alert('zip is '+myZip);
}
}
}
else
{
alert("Error: returned status code "+req.status+" "+req.statusText);
}
})(req.responseText);
}
}
req.send();
alert(myZip);
return myZip;
You should either use a callback instead of return statement, or you should run this as Stratified JavaScript: http://stratifiedjs.org.
Then you can write it in a synchronous fashion, like you kind of did, even though it will NOT block your browser.
I guess you use the same object(req) a couple of times and will be overwritten on each loop.
So use separate objects for every requests or start a new request if the last one is finished.
How exactly you can do this I cannot say without knowing what req is.

Categories

Resources