Lately I've been experimenting with a technique for automatically converting ASP.Net postback events (the onclick event of an ASP.Net button initially, but there's no reason it would work with the postback event of any ASP.Net control) to Ajax calls using JQuery, much lighter than the calls made using Microsoft Ajax too. I think it should work however it's not fully implemented yet.

Here's a brief overview of the technique...

The way we do this on Frooly is a little more complex but for the sake of example, lets say we wrap all our controls in div of id "wrapper" followed by a unique ID, and include a hidden field containing our control address, Like this:
<div id="wrapper">
<asp:HiddenField ID="HiddenFieldControlAddress" Value="Controls/CreateProduct.ascx" runat="server" />
</div>

use a JQuery event to intercept the postback (in this case an ASP.Net button click), and then grab the id of the submitting button, the id of the wrapper div, then grab the id, the (URL encoded) value and the control address of each of the input controls within the wrapper , before sending them via the usual JQuery ajax call to our receiving method on server side
$("div[id^='wrapper]").find(":submit").click(function() {
//Grab the ID of the button
var submittingControlId = $(this).attr("name");
//grab the wrapper ID
var wrapperId = $(this).closest("div[id^='wrapper]").attr("id");
//child inputs
var valueString = "";
$(this).closest("div[id^='wrapper]").find("input").each(function() {
valueString = valueString + "&i=" + $(this).attr("id");
valueString = valueString + "&v=" + URLEncode($(this).val());
valueString = valueString + "&p=" + $(this).closest("div[id^='cntItem_']").attr("id");
valueString = valueString + "&t=" + $(this).closest("div[id^='cntItem_']").children("#cntrlAddr").val();
valueString = valueString + ",";
});

//Send via Ajax...
TryAjaxCall(wrapperId, submittingControlId, valueString);
});


Then, after receiving our data, we go through it, re-instantiating our controls using
Control.LoadControl(controlAddress);
I'm skipping over a lot here, but basically for each control address we collected, we repopulate the data using the corresponding IDs and Values, then call our the event using reflection - the reflection bit is a bit complicated but it looks something like this:
System.Web.UI.WebControls.Button button = (System.Web.UI.WebControls.Button)control;
Type t = typeof(Button);
object[] p = new object[1];
p[0] = EventArgs.Empty;
MethodInfo m = t.GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance);
m.Invoke(button, p);

Having triggered the event, we render our parent control markup to a string, return that string via Ajax to our page and replace the markup of the parent control on the page.

I've been deliberately vague on the detail while I figure out all the niggles, it's at a very experimental stage at the mo, but I thought I'd talk about it since I've found no examples of anyone doing anything similar.

I'm concious that it's not always an appropriate option but if your web application builds its pages from individual WebControls (as Frooly does) it offers a number of advantages:
  • it allows you to perform a call which only posts back the contents of that control and in response only updates that control (keeping the calls nice and light)
  • it requires no extra work on the part of the developers when creating new controls to enable Ajax
  • it still works in postback mode if Javascript is turned off
  • we can automate pretty loading animations
  • best of all since we're controlling the entire transaction end to end, we can automate our client and server side validation
Has anyone else tried anything like this?

0 comments:

Post a comment

top