In my current project, I’m doing some fancy-pants stuff to lookup UK addresses via a web service, then send them to the client using JSON. On the client end, I’m displaying the results in an ibox and then sending the results back to the main form. Woah!
The first challenge was getting the ibox to open and display the form correctly. I chose to use a hidden div as my “form”, and let the ibox display it on the screen when appropriate. It all seemed to work correctly, however when I tried to read the values out of the fields on the ibox form, it kept telling me they were empty!
After a lot of mucking around, cursing, and rude gestures directed at the computer – you know, the standard debugging drill – I worked out that when you use a hidden div as your ibox, it actually *clones* the entire InnerHTML of the hidden div! So in effect, you get *two* of every field with duplicate IDs. And, since the HTML generated by ibox goes at the *end* of your document, when you call document.getElementById, you get back the *first matching element*, which will always be the one that’s still safely hidden away in your form. Handy – not!!
But never fear, the solution is actually quite simple. You just have to create an external file containing your ibox form, and then use that as the HREF in your link:
<a href="FindAddress.aspx" rel="ibox&height=400" title="Find an address">Find address</a>
Ahh, finally things started working properly! So now that I could read the postcode that the user entered, I wanted to hit a handler to…. err… “handle” the web service request. To do that, I used prototype.js – a javascript library with a whole bunch of wicked cool functionality (all of which is way beyond the scope of this article). Check it out -to execute a cross browser friendly AJAX request, you simply do this:
var url = "Handlers/FindAddressHandler.ashx?Id=" + id;
new Ajax.Request(url, {
onSuccess: OnAddressFound,
onFailure: OnError
});
Of course, you can inline the callback functions, but I wanted to separate them for readability. Anyway, the next part was setting up the FindAddressHandler. I won’t go into too much detail here as it’s just a standard implementation of IHttpHandler which then hits a web service. The part I want to talk about though is writing back the address object using JSON. A dude named Jason Newton King has written a brilliant library called Json.NET which makes life a hell of a lot easier!
Basically, you just have to create a JsonWriter, then serialise the properties of your object that you want to send back to the client. So in my case with an Address object (stored in local variable “address”):
StringBuilder builder = new StringBuilder();
using (JsonWriter writer = new JsonWriter(new StringWriter(builder))) {
writer.WriteStartObject();
writer.WritePropertyName("PostCode");
writer.WriteValue(address.Postcode);
writer.WritePropertyName("Address1");
writer.WriteValue(address.Line1);
writer.WritePropertyName("Address2");
writer.WriteValue(address.Line2);
writer.WritePropertyName("Address3");
writer.WriteValue(address.Line3);
writer.WritePropertyName("PostalTown");
writer.WriteValue(address.PostTown);
writer.WriteEndObject();
writer.Flush();
}
_context.Response.AddHeader("X-JSON", builder.ToString());
Easy, right? So the thing to note here, besides how simple it is to persist your object in JSON, is that I’m sending back the JSON string in a response header called “X-JSON”. Now back on the client side again – one of the bonus features of Prototype is that it automatically interprets whatever is in the “X-JSON” header, and builds your objects for you! So, here’s the code I wrote for my client-side callback:
function OnAddressFound(transport, address) {
$("txtAddress1").value = address.Address1;
$("txtAddress2").value = address.Address2;
$("txtAddress3").value = address.Address3;
$("txtPostCode").value = address.PostCode;
$("txtPostalTown").value = address.PostalTown;
hideIbox();
}
The first argument – transport – is the XmlHttpRequest object which was used. (You can find a great document which outlines the properties of the XmlHttpRequest object on the Apple Developer Connection website). The second argument is the object which Prototype interpreted from the X-JSON response header. You can see also that prototype implements a function – $ – which is effectively a suped-up version of document.getElementById.
Using all of these technologies together was surprisingly easy! I’m super impressed with how you can grab so many rich frameworks to enhance your websites, all for free!