Tuesday, July 24, 2012

Cross Domain AJAX Calls with PhoneGap and jQuery

When creating a PhoneGap app, you are essentially creating a web page and it lives in the 'localhost' domain. Unfortunately, by default AJAX calls are only supported in the same domain - unless you use JSONP (JSON with padding). You can read more about JSONP here: http://en.wikipedia.org/wiki/JSONP

Create the Mobile Web Page

Ok, let's cheat... well, is saving time cheating?  I went to http://jquerymobile.com/ and used the prototyping tool and built a quick HTML5 page.
















When I was finished, I clicked the "Download HTML" button and was given a neat little zip file with a web page, a CSS file and a JS file. I renamed the CSS and JS files to demo.* and copied them into my PhoneGap www\include folder.

I dropped the HTML page into the www folder and opened it in the editor.  I modified the HTML file to reference the newly added CSS and JS. I renamed the HTML file to ajaxdemo.html.  I also had to update the main java file of the PhoneGap app.

public void onCreate(Bundle savedInstanceState)  
   {  
     super.onCreate(savedInstanceState);  
     //setContentView(R.layout.main);  
     super.loadUrl("file:///android_asset/www/ajaxdemo.html");  
   }  

For a quick test, I viewed the HTML file in a browser to make sure it looks OK.  I could, at this point, compile and run the app in my phone.

Add a PHP Page to Call With AJAX

This is a very simple PHP page.  All we want to do is take some parameters from the Request and return a JSON object wrapped in a JSONP function.  You'll see what I mean when you read the code. I call this name.php.

firstname = $_GET['first'];  
 $theName->lastname = $_GET['last'];
  
 echo $_GET['callback'] .'('. json_encode($theName) . ')';  
 ?>  

The first lines simply grab the request values from the GET collection and assign it to a dynamically created object. PHP is like JavaScript in that you can create an object's members on the fly.

The JSONP part of this return is the
echo $_GET['callback'] .'('. json_encode($theName) . ')'
part.  When we create the actual AJAX request, we will declare a function in which to wrap our JSON response. This is part of our GET request. You'll see more when we build the AJAX request.

The PHP function json_encode()  is handy for taking your object or collection and turning it into a JSON object. You can find more info here.

I uploaded this file to my hosting account, so I can call it from my local code. After uploading, I can simulate the AJAX call with the following URL:
http://mysite.com/name.php?callback=jp&first=pat&last=buff

If you've copied my code correctly, you should see results that look like:
jp({"firstname":"pat","lastname":"buff"})

Now For AJAX and other JavaScript

The server-side code is in place.  Let's add the JavaScript.
    function appReady(){  
       $("#infodiv").html("Testing JSONP with jQuery");  
     }  
   
     $(document).ready(function(){  
       $("#get-name").click(function(){  
         handleClick();  
       });  
   
       $("#ajax_error").ajaxError(function(e, jqxhr, settings, exception) {  
         $(this).text( "Error requesting page " + settings.url);  
       });  
     });  
   
     document.addEventListener("deviceready", appReady, false);  
   
     $( document ).bind( "mobileinit", function() {  
       // Make your jQuery Mobile framework configuration changes here!  
       $("#infodiv").html('mobileinit worked');  
       $.mobile.allowCrossDomainPages = true;  
     });  
   
     function handleClick(){  
       var url = 'http://fineglasswork.com/histmarkers/client/partial.php';  
   
       $.ajax({  
         type: 'GET',  
         url: url,  
         contentType: "application/json",  
         dataType: 'jsonp',  
         data: {first: $("#firstname").val(), last: $("#lastname").val() },  
         crossDomain: true,  
         success: function(res) {  
           $("#resultsdiv").html("Hello, " + res.firstname + " " + res.lastname);  
           console.dir(res.fullname);  
         },  
         error: function(e) {  
           console.log(e.message);  
         },  
         complete: function(data) {  
           console.log(e.message);  
         }  
       });  
   
     }  

The guts of this script - the part we want to focus on - is the handleClick() function.  This is where we make our AJAX call with jQuery. We should pay special attention to these parameters:

         contentType: "application/json",  
         dataType: 'jsonp',  
         data: {first: $("#firstname").val(), last: $("#lastname").val() },  
         crossDomain: true,  

Declaring the dataType as 'jsonp' will automatically add the 'callback' parameter to the GET request. crossDomain is set to true (of course! otherwise we wouldn't need to use JSONP). The data is passed as a JSON object.  The data elements will automatically be added to the GET request for us - no need to build a URL with a querystring.

We are ready to run our code!  I usually use my HTC Evo, but in this case, I ran it with an emulator so I could get this beautiful screen shot.  I entered a first name and last into the Text fields and clicked the "Click Me" button to get this result.













Now isn't that just gorgeous!

Something you might notice is that the heading is different when you see the page in your browser.  That's because we modify that header in the appReady handler.  The appReady handler is defined in this line:
    document.addEventListener("deviceready", appReady, false);  
The deviceready event is used to notify the app that PhoneGap is loaded.  When writing PhoneGap apps, you should wait until deviceready event is called before depending on any PhoneGap functionality to be available.

That's it for now!  I hope this was helpful.  Please feel free to ask questions or suggest changes.

Edit: I've uploaded the code in this Post to GitHub. https://github.com/RichBuff/PhoneGap-App-with-JSONP-AJAX-Call


You can also find this article on my new blog site: http://alpheussoftware.com/?p=20


































1 comment:

  1. Dear Rich, I tried to compile your code on phonegap build. The resulting apk does not work. "Click Me" button does not register...Could you please help.

    ReplyDelete