Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts

Tuesday, May 29, 2012

How to debug AJAX

One of the things I do is mentor junior and young web developers. One of the most asked question is how to debug AJAX, XMLHttpRequests, also known as XHR.

Well, it is very easy. In most modern web browsers, there are web developer tools. There are native tools built in IE, Safari and Chrome. They are often called Web/Developer Inspectors. With Firefox, you can use Firebug.

Each browsers are different in how you access the XHR console. I won't go into details but it is very easy to find. Launch your web inspector or right-click and "inspect element" before you make your AJAX call. When the web developer tool (called by various names and differing across versions of the same browsers). Look for resources or Network. Then narrow down for scripts or XHR (short for XMLHttpRequest) options.



Below are screenshots of Chromium under Ubuntu 10.10 and Safari under Mac OSX.




Whenever I make an AJAX call, I look for the script/resource I am calling. In my screenshot above, I am both calling a script called ajax/_ajax_sample.php.

Here is the HTML I use to call my AJAX. It is a simple AJAX post, passing some variables in a form-like POST.

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
 <head> 
 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"</script> 
 <script type="text/javascript"> 
 $(document).ready(function() { 
 $.ajax({ 
 type: "POST", url: "ajax/_ajax_sample.php", data: { action: 'update file', user_name : 'joe blow', user_id: 100 }, 
 dataType: "json", 
 success: function(data){ 
 if(data.status == 'success'){ 
 if (data.post_action == 'show_div') { $("#results_div").html(data.msg); } 
 } else { 
 alert( "There was an error: " + data.msg); 
 } 
 } // end of data.status = success 
 }); // end of ajax 
 }); 
 </script> 
 <html><body> 
 Results: 
 <div id ="results_div" style="display:block;width:400px;background-color:#CCCCCC">Nothing Yet</div> 
 </body></html> 


If you go back and look at the two browser screen grabs, I am passing the following POST data. This is indicated in the "Header" tabs. The Header's tab is what you post to your resource. You will see other behind-the-scene info such as Request Headers, the method, and the Response Headers (how the server informs the browser it will process).

For our purposes, they only thing I am looking for is the "Form Data" of what I posted. I just need to know if what I posted was correct. They are:

 action:update file 
 user_name:joe blow 
 user_id:100 

My script or resource will takes the Form Data Post  from my AJAX call in the same manner you would be sending data through a HTML form or query string.

This is how you check you are posting the right data or not.

When your CGI resource or script gets the request, it will eventually return some data. The web inspector will also you give a read-out between the time it gets the request to the time it finishes. You can see how efficient your back-end code is.  See below for example of latency and processing time.



The results  are often HTML data or JSON. To see what it returns, simply click on the "Content" tab. There may be other tabs such as preview or JSON to show the same results.

As you can see in the next screenshot, my result was in JSON. If you go back and look at the same HTML file posted, I take the JSON and use it to execute another javascript function based on what I got back. Namely, filling the data into a DIV called results_div. The status return a 'success'.

 {"status":"success","msg":"your ajax worked mr\/mrs joe blow","post_action":"show_div","record_id":40} 







Now, in this next screenshot, I introduced some errors. My HTML page tried to make 2 ajax calls and got 404 errors which means the page could not find the two file resources.

The third error, I introduced some errors on my PHP script. The web inspector returned a 500 Internal Server Error. My AJAX is passing the correct data but there was something wrong with the PHP. 

Fortunately, I have a terminal window above to tail (monitor) my apache logs for PHP errors. By running tail -f  on my apache error_log, I can see the error is in line 6 of my PHP script. It is handy to have a big enough monitor to see and debug your web application.



This is the most common problem I see when a new web developer starts to use plugins, free lightboxes, modals, and unknown scripts. They simply see an animated AJAX spinning wheel and can't figure our why the page isn't do anything. By using their browser developer's inspection tool, they can see if they are not linking correctly or if simply their back-end is broken.

Thursday, May 24, 2012

JQUERY AJAX style upload with callback

By now, you have probably seen websites with "AJAX" style upload. Technically many of them are not really AJAX. XMLHttpRequest (AJAX) upload is not technically possible due to security limitations of Javascript. However, we still call them AJAX uploaders because they act and feel like it to the end-user; meaning the web pages are posting files without refreshing.

So where are the "AJAX uploaders?"


Many of them are actually SWF (Flash based) uploaders billed as "jquery file upload plugins." I'm sure many of them work great but I prefer to avoid Flash as much as possible.

There are also HTML5 support in some new browsers for asynchronous file uploads via AJAX post but I've had problems with some browsers like Safari and problems with different file types.


Today, I will show you how to simulate an AJAX upload without the use of Flash. If you have done some googling, the most common way to do it is to use a hidden iframe. This is considered a hack but it works. There are some tutorials out there but mine will show you how to get a callback from your upload script using Jquery. You can use pure Javascript but Jquery is very convenient.
A callback will be a JSON reply that the host page (the one doing the upload) can retrieve and act upon. For example, if the upload failed, you can notify the user. Or you can pass the record ID of the file after it was stored in a database.


First, you need to add a hidden iframe (mine is called upload_hidden) to your upload page.





 <body> 
 <iframe id="upload_hidden" name="upload_hidden" src="blank.html" style="display:none;"></iframe> 
 <form enctype="multipart/form-data" method ="POST" action ="upload_json.php" id ="upload_form"> 
 <input type="file" name="upload_file"><button name="Upload" type="submit" value ="Upload">Upload</button> 
 </form> 
 </body> 


Then you need to set the form to post to the hidden frame.


 function setTarget() { 
 document.getElementById('upload_form').onsubmit=function() { document.getElementById('upload_form').target = 'upload_hidden';} 
 } 

Then make sure you call it onload.


 window.onload=setTarget; 


Now for the pseudo callback. The trick is to check every time the iframe loads new content and parse the results. The way I do it is to embed my JSON reply in a div from the upload script.

After processing my upload, my PHP code generates the JSON wrapped in a DIV.


 <?php 
 $finished = array ('status'=>'success','time'=>date('Y-m-d H:i:s',time()),'db_insert_id'=>$record_id, ); 
 echo "<div id ='upload_status'>"; 
 echo json_encode($finished); 
 echo "</div>"; ?> 

And here is my JQuery code to parse the JSON from the PHP loaded into the hidden div.
 $(document).ready(function() { 
 $('#upload_hidden').load(function() { 
 var a = $("#upload_hidden").contents().find("#upload_status").html(); 
 if (a !=null) { 
 var obj = jQuery.parseJSON(a); 
 if (obj.status == 'success') { 
 alert ("file to saved to db as " + obj.db_insert_id); 
 } // #end success 
 } // #end a!=null 
 }); // #end upload_hidden load 
 }); 

The key thing to note are:
a = $("#upload_hidden").contents().find("#upload_status").html();
and
obj = jQuery.parseJSON(a)

Every time the iframe is loaded, I look inside the iframe for anything inside a div called "upload_status." When the iframe is initially loaded with a blank placeholder, nothing happens because the content is empty. However, when it detects anything, I parse whatever is inside the div as my JSON string.


After uploading a file, here are the results. Obviously, you would need to hide the iframe after you do some testing.

To wrap up. This is one way to handle callbacks in an pseudo-AJAX file upload. There are probably other ways to do it but this was something quick and works for my needs.
Here is the example code.
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
 <html xmlns="http://www.w3.org/1999/xhtml"> 
 <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
 <title>Example</title> 
 <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script> 
 <script type="text/javascript"> 
 function setTarget() { 
 document.getElementById('upload_form').onsubmit=function() { document.getElementById('upload_form').target = 'upload_hidden';} 
 } 
 $(document).ready(function() { 
 $('#upload_hidden').load(function() { 
 var a = $("#upload_hidden").contents().find("#upload_status").html(); 
 if (a !=null) { 
 var obj = jQuery.parseJSON(a); 
 if (obj.status == 'success') { 
 alert ("file to saved to db as " + obj.db_insert_id); 
 } // #end success 
 } // #end a!=null 
 }); // #end upload_hidden load 
 }); 
 window.onload=setTarget; 
 </script> 
 </head> 
 <body> 
 <iframe id="upload_hidden" name="upload_hidden" src="blank.html" style="display:none;"></iframe> 
 <form enctype="multipart/form-data" method ="POST" action ="upload_json.php" id ="upload_form"> 
 <input type="file" name="upload_file"> 
 <button name="Upload" type="submit" value ="Upload">Upload</button> 
 </form> 
 </body> 
 </html> 
Subscribe to: Comments (Atom)

AltStyle によって変換されたページ (->オリジナル) /