Hi Everyone! I'm currently working on MySQL/PHP/JavaScript project using AJAX. I came across some weird abnormality and wanted to share with you and hopefully find a solution to this problem.

for some reason alert(textarea2); shows nothing but if I place another alert(textarea2); right after the first one it works, second pop-up contains responseText....

also I've tried alert(resp.responseText); it worked fine, could someone please point me in the right direction, i really need some assistance, cheers!

new Ajax.Request("categories-inset.php", 
		{ 
		method: 'get', 
		parameters : "divid=1&catid=14&subcatid=31",
			
			onSuccess : function(resp) 
			{
				
				textarea2=resp.responseText;
			 
			 }
			 ,
			 onFailure : function(resp) 
			 {
			   alert("Oops, there's been an error.");
			 }

		});
alert(textarea2);

Ablitz,

Take a deep breath and read carefully .....

This is actually not so weird. Remember that the "A" in "AJAX" stands for "asynchronous". This means that once an AJAX request has been made, there are two "code streams". (To muddy the waters a bit, javascript is single threaded so we can't say "two threads" but in concept, that's what happens).

In other words, the "mainstream" code (which made an AJAX request) marches on to completion without waiting for the AJAX reposnse to come back. The AJAX response has its own agenda, independent of the mainstream, and is dependent on the server serving its response.

Therefore, when your code makes its request (new Ajax.Request() with its various parameters) there is every chance that it will immediately proceed to the first alert(textarea2) before "categories-inset.php" has been served into the AJAX object.

There then follows a lengthy period (in code execution timescales) while the alert is presented, you read the message and get the cursor over the OK button.

While the alert is presented, two things happen:

  • Execution of your second alert(textarea2) is held up.
  • categories-inset.php has time to repond, and hence fire the "onsuccess" function, populating the textarea2 variable with its response.

When you click the first alert's OK button, your mainstream code is released to continue and the second alert(textarea2) is executed. The second alert(textarea2) presents categories-inset.php's responseText.

If you've followed all that, then you will also spot there's actually no guarantee that categories-inset.php will have reponded while the first alert is presented (the server and/or the interenet may be running slow). Therefore, it is entirely possible that the second alert will be exactly the same as the first (a null message). For this reason, you shouldn't put any response handling statements in the "mainstream" code. This is precisely why you have an "onsuccess" handler (and typically an onFailure handler as well). So if you were to replace textarea2=resp.responseText; with alert(resp.responseText); , you would observe exactly what you are expecting.

You may well need to read this through a couple of times. I have done so to make sure it makes sense, and I think it does - but I wrote it. Make the effort to understand the basics or AJAX will always be a mystery. There are many tutorials on the web to flesh out my sketchy description.

Hope this helps.

Airshow

Ablitz,

Take a deep breath and read carefully .....

This is actually not so weird. Remember that the "A" in "AJAX" stands for "asynchronous". This means that once an AJAX request has been made, there are two "code streams". (To muddy the waters a bit, javascript is single threaded so we can't say "two threads" but in concept, that's what happens).

In other words, the "mainstream" code (which made an AJAX request) marches on to completion without waiting for the AJAX reposnse to come back. The AJAX response has its own agenda, independent of the mainstream, and is dependent on the server serving its response.

Therefore, when your code makes its request (new Ajax.Request() with its various parameters) there is every chance that it will immediately proceed to the first alert(textarea2) before "categories-inset.php" has been served into the AJAX object.

There then follows a lengthy period (in code execution timescales) while the alert is presented, you read the message and get the cursor over the OK button.

While the alert is presented, two things happen:

  • Execution of your second alert(textarea2) is held up.
  • categories-inset.php has time to repond, and hence fire the "onsuccess" function, populating the textarea2 variable with its response.

When you click the first alert's OK button, your mainstream code is released to continue and the second alert(textarea2) is executed. The second alert(textarea2) presents categories-inset.php's responseText.

If you've followed all that, then you will also spot there's actually no guarantee that categories-inset.php will have reponded while the first alert is presented (the server and/or the interenet may be running slow). Therefore, it is entirely possible that the second alert will be exactly the same as the first (a null message). For this reason, you shouldn't put any response handling statements in the "mainstream" code. This is precisely why you have an "onsuccess" handler (and typically an onFailure handler as well). So if you were to replace textarea2=resp.responseText; with alert(resp.responseText); , you would observe exactly what you are expecting.

You may well need to read this through a couple of times. I have done so to make sure it makes sense, and I think it does - but I wrote it. Make the effort to understand the basics or AJAX will always be a mystery. There are many tutorials on the web to flesh out my sketchy description.

Hope this helps.

Airshow

Hi thank you for taking time to help out, I got the idea how it works so my question is how do I wait for the function to complete? and what about onSuccess function , how come that isnt working, isnt it suppose to kinda loop the code till it returns something? thx again

... how do I wait for the function to complete? ...

That's the clever thing about AJAX, you don't have to wait - at least not in the conventional way. Your code establishes a 'listener' with the code onSuccess : function(resp) {textarea2=resp.responseText;} . This function fires automatically if/when the requested file successfully returns a response.

... and what about onSuccess function , how come that isnt working, isnt it suppose to kinda loop the code till it returns something?

I think it is working. Remember my suggestion to replace textarea2=resp.responseText; with alert(resp.responseText); ? (I should also have said to delete all other alerts) If you try what I suggest then the response from "categories-inset.php" should be reliably displayed.

Airshow

That's the clever thing about AJAX, you don't have to wait - at least not in the conventional way. Your code establishes a 'listener' with the code onSuccess : function(resp) {textarea2=resp.responseText;} . This function fires automatically if/when the requested file successfully returns a response.

Thx again for dedicating yr time, I've finally got the above point. You see the thing is, categories-inset.php returns 3 SELECT boxes. User doesnt see them at first only when AJAX code triggered. When code is executed, javascript creates a new DIV and insertHTML those 3 SELECT boxes. Now because of that delay i get a blank DIV.

I think it is working. Remember my suggestion to replace textarea2=resp.responseText; with alert(resp.responseText); ? (I should also have said to delete all other alerts) If you try what I suggest then the response from "categories-inset.php" should be reliably displayed.

Airshow

I did try this previously and yes it did work, alert(resp.responseText); returns html table with 3 SELECT boxes.

Do you know by any chance how can i solve this problem? would new Ajax.Updater make any difference?

i just tried using Updater, looks like it serves completely different purpose, i really need that responseText to fill constructed div...

Mate thank you so much for explaing to me how it all works, your comments helped me understand the process and i came up with a following solution its all works now!!! :))) I even managed to add a loading gif ;)

if((obj.id).substr(0,4)=='divi')
	{
		  textarea = '<div id="'+obj.id+'_editor">';
		textarea+='<img src="images/ajax-loader.gif" />';

			button = '</div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>';
 	new Insertion.After(obj, textarea+button);	
		
	Event.observe(obj.id+'_save', 'click', function(){saveChanges(obj)}, false);
	Event.observe(obj.id+'_cancel', 'click', function(){cleanUp(obj)}, false);
		 new Ajax.Request("categories-inset.php", 
		{ 
		method: 'get', 
		parameters : "divid=1&catid=14&subcatid=31",
			
			onSuccess : function(resp) 
			{
				document.getElementById(obj.id+"_editor").innerHTML=resp.responseText;
			 
			 }
			 ,
			 onFailure : function(resp) 
			 {
			   alert("Oops, there's been an error.");
			 }

		});

Ablitz,

Waaaaahaaaay! There's a certain satisfaction in getting code to work. I think you are feeling it right now. Well done, my contribution was minimal.

There's something you might like to watch when building strings in Javascript. It may not matter too much here but with sunstantial Ajax applications, web pages tend to have a long life in users' browsers so you really need to do everything you can to avoid memory leakage.

Javascript is prone to nasty memory leaks if you concatenate strings with xxx = xxx + yyy or xxx += yyy .

You might consider rewriting:

textarea = '<div id="'+obj.id+'_editor">';
textarea += '<img src="images/ajax-loader.gif" />';
button = '</div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>';

as the single statement:

textarea = '<div id="'+obj.id+'_editor"><img src="images/ajax-loader.gif" /></div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>';

You can do this because you concatenate textarea+button just after they are created (and as far as I can see, you don't need the separate parts).

Somtimes you need to build strings in a loop. At first it appears that you can't avoid + or += , which can get very expesive in memory. Well it just happens that Javascript Arrays are really cheap and they have a great method join() . Therefore, you can build strings piecemeal, in an array, then eventually join the pieces. Though it's overkill here, the following is actually efficient javascript.

myStringArray = [];
myStringArray.push('<div id="'+obj.id+'_editor">');
myStringArray.push('<img src="images/ajax-loader.gif" />');
myStringArray.push('</div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>');
new Insertion.After(obj, myStringArray.join(''));
// .......

Note: We join with join('') , because join defaults to join(',') (which can be good on other occasions).

There's a bunch of other leak-avoidance stuff to be aware of in javascript (with particular reference to Ajax). Google "javascript memory leak" or "ajax memory leak" for some discussions. The book "Ajax in Action" (Crane D, Pascarello E & James D; MANNING, 2006; ISBN 1-932394-61-3) includes a good section on memory leakage and what to do/avoid.

Anyways, that's all detail. Congrats on getting your code working.

See you here on Daniweb again some time no doubt.

Airshow

Comments
Very dedicated and helpful! Thank you!

Hi, the first A in Ajax is for asynchronous, BUT, you can set the call to behave Synchronous, so your alert will wait until the request is finished. Just add the following to your request options:

asynchronous: false, so your new code will look like:


new Ajax.Request("categories-inset.php", 
		{ 
		method: 'get', 
                asynchronous: false, // <---  ADD THIS
		parameters : "divid=1&catid=14&subcatid=31",
			
			onSuccess : function(resp) 
			{
				
				textarea2=resp.responseText;
			 
			 }
			 ,
			 onFailure : function(resp) 
			 {
			   alert("Oops, there's been an error.");
			 }

		});
alert(textarea2);

by default this is set to true, so it becomes AJAX :-D. with the value of false it behave just like any other request. Note that if your request takes some time executing you will add that time to your total execution time..

refer to http://www.prototypejs.org/api/ajax/options for documentation on how prototype works.

.::AleX::.

Hi, the first A in Ajax is for asynchronous, BUT, you can set the call to behave Synchronous, so your alert will wait until the request is finished. Just add the following to your request options:

asynchronous: false, so your new code will look like:

by default this is set to true, so it becomes AJAX :-D. with the value of false it behave just like any other request. Note that if your request takes some time executing you will add that time to your total execution time..

refer to http://www.prototypejs.org/api/ajax/options for documentation on how prototype works.

.::AleX::.

wow thx mate, some interesting info! I'll give it a go!

Ablitz,

Waaaaahaaaay! There's a certain satisfaction in getting code to work. I think you are feeling it right now. Well done, my contribution was minimal.

There's something you might like to watch when building strings in Javascript. It may not matter too much here but with sunstantial Ajax applications, web pages tend to have a long life in users' browsers so you really need to do everything you can to avoid memory leakage.

Javascript is prone to nasty memory leaks if you concatenate strings with xxx = xxx + yyy or xxx += yyy .

You might consider rewriting:

textarea = '<div id="'+obj.id+'_editor">';
textarea += '<img src="images/ajax-loader.gif" />';
button = '</div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>';

as the single statement:

textarea = '<div id="'+obj.id+'_editor"><img src="images/ajax-loader.gif" /></div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>';

You can do this because you concatenate textarea+button just after they are created (and as far as I can see, you don't need the separate parts).

Somtimes you need to build strings in a loop. At first it appears that you can't avoid + or += , which can get very expesive in memory. Well it just happens that Javascript Arrays are really cheap and they have a great method join() . Therefore, you can build strings piecemeal, in an array, then eventually join the pieces. Though it's overkill here, the following is actually efficient javascript.

myStringArray = [];
myStringArray.push('<div id="'+obj.id+'_editor">');
myStringArray.push('<img src="images/ajax-loader.gif" />');
myStringArray.push('</div><div id="'+obj.id+'_controls"><input id="'+obj.id+'_save" type="button" value="SAVE" /> OR <input id="'+obj.id+'_cancel" type="button" value="CANCEL" /></div>');
new Insertion.After(obj, myStringArray.join(''));
// .......

Note: We join with join('') , because join defaults to join(',') (which can be good on other occasions).

There's a bunch of other leak-avoidance stuff to be aware of in javascript (with particular reference to Ajax). Google "javascript memory leak" or "ajax memory leak" for some discussions. The book "Ajax in Action" (Crane D, Pascarello E & James D; MANNING, 2006; ISBN 1-932394-61-3) includes a good section on memory leakage and what to do/avoid.

Anyways, that's all detail. Congrats on getting your code working.

See you here on Daniweb again some time no doubt.

Airshow

Yeah mate, u feeling me for sure;) The feeling is priceless! Well to me your explanation did the trick and I've looking for a solution for awhile. asking on forums was a last resort. I wish i've done sooner though:)) but its coool anywayz its all good now:)

thank you for your extra tips too! im new to javascript and php. all those bits of info help heaps!

I have Java/J2EE/J2SE background but recently tried PHP and now i dont wanna go back to Java, its just so simple and straight forward...

+1 to yr reputation;)

This question has already been answered. Start a new discussion instead.