CategoryUpdatePanel

UpdatePanels and JavaScript request events

When my journey continued in the land of UpdatePanels (read my previous post about UpdatePanels here), I was looking for a way to create a clientside success event handler. I have been working with jQuery for some years now so I’ m a bit spoiled when it goes about Ajax. Their framework makes it very easy to register success or error handlers:

$.ajax({
   url : "/someurl",
   type: "POST",
   success: function(data) {
      // your success handling here
   }
});

I was hoping to find some what the same for partial postback requests. After researching the web for a while, I took a look at the Sys.WebForms.PageRequestManager object. This singleton object holds all data relevant to async page requests and holds some useful functions for registering your functions as event handlers.

In this case, I was looking for two events, the begin and end request events. The begin request  event handler can be registered by using the add_beginRequest function and the end request handler by using the  add_endRequest function.

var requestManager = Sys.WebForms.PageRequestManager.getInstance();
requestManager.add_beginRequest(function(sender, args) {
    // begin request logic here
});
requestManager.add_endRequest(function(sender, args) {
    // end request logic here
});

The event handlers are called with two arguments: The PageRequestManager (sender in this example) and the EventArguments (args in this example). These are very important to determine which UpdatePanel or PostBack element (Button, etc) is triggering the request.

The BeginEventArguments exposes three interesting functions:

  • a get_postBackElement function for retrieving the element that caused the PostBack.
  • a get_updatePanelsToUpdate function for retrieving a list of UniqueIds of the UpdatePanels which will be updated by this request.
  • a get_request function for retrieving the event context.
   var requestManager = Sys.WebForms.PageRequestManager.getInstance();
   requestManager.add_beginRequest(function(sender, args) {
     var postBackElement = args.get_postBackElement();
     var updatePanels = args.get_updatePanelsToUpdate();
     var request = args.get_request();
   });

The EndRequestArguments exposes five functions, two are very useful for my case.

  • a get_error function for retrieving the error. This function will return null when no error has occurred.
  • a get_response function to retrieve the response.
var requestManager = Sys.WebForms.PageRequestManager.getInstance();
requestManager.add_endRequest(function(sender, args) {
    var error = args.get_error();
    var response = args.get_response();
    if (error) {
       // handle error
    }
});

The PageRequestManager contains a lot more useful functions and properties for hooking up to the webforms ajax system.
Some I like are abortPostBack, get_isInAsyncPostBackremove_beginRequest and remove_endRequest.

UpdatePanels and JavaScript triggers

Sometimes, you don’t get to choose between WebForms and MVC (for instance when you’re doing some rework on an old project).
So I got stuck on a WebForms project and I’m more a MVC kinda guy.
Some reasons why I like MVC over WebForms:

  • Flexibility
  • Unit testable
  • Stateless
  • Clean html output

Some people say that you have to write more html with MVC, but I don’t really agree. When you make good use of the HtmlExtensions, DisplayTemplates and EditorTemplates, it is just the same and even more flexible.
But that’s not what this post is about.
When I was working on this WebForms project, I was creating a page with multiple UpdatePanels and that’s when the trouble started.
I wanted to update the UpdatePanel form outside the UpdatePanel, so there was no use in defining triggers. The trigger was coming from a JavaScript function.
After doing some research, I read about the __doPostBack function. This function allows you to update an UpdatePanel and takes two arguments. The first argument is the ClientID of the UpdatePanel:

<asp:UpdatePanel runat="server" ID="upDemo">
  <ContentTemplate>
    <h1>Inside the UpdatePanel</h1>
  </ContentTemplate>
</asp:UpdatePanel>

The following JavaScript code will trigger an update of the UpdatePanel in the demo above:

__doPostBack("<%= upDemo.ClientID %>", "some argument");

The second argument of the __doPostBack function is the event argument. This is a very nice feature, because this allows you to send an ID or some extra data. You can even send a json object if you want.

But now we need to intercept the data in the code behind. The __doPostBack causes a PostBack so all events of the page cycle will occur.  In the page load we can intercept the ajax event.

First of all, there is the ScriptManager. This manager handles the Ajax requests and provides useful data.

protected void Page_Load(object sender, EventArgs e)
{
  var scriptmanager = ScriptManager.GetCurrent(this);
  var isAjaxRequest - scriptmanager.IsInAsyncPostBack;
}

This code example shows how the ScriptManager exposes the IsInAsyncPostBack property. This property helps to determine if the request is an ajax request (Similar to Request.IsAjaxRequest in MVC). But what if you have more than one UpdatePanel? Which panel is causing the ajax request?
I found two ways to determine this, The first one is again the ScriptManager:

protected void Page_Load(object sender, EventArgs e)
{
  var scriptmanager = ScriptManager.GetCurrent(this);
  if (scriptmanager.IsInAsyncPostBack
   && scriptmanager.AsyncPostBackSourceElementID == upDemo.ClientID)
  {
    // we now know that the postback is caused by the upDemo UpdatePanel
  }
}

The AsyncPostBackSourceElementID holds the ClientID of the UpdatePanel which caused the PostBack.
The second way is by using  the Form values from the Request:

protected void Page_Load(object sender, EventArgs e)
{
  var target = this.Request.Form["__EVENTTARGET"];
  var scriptmanager = ScriptManager.GetCurrent(this);
  if (scriptmanager.IsInAsyncPostBack && target == upDemo.ClientID)
  {
    // we now know that the postback is caused by the upDemo UpdatePanel
    var argument = this.Request.Form["__EVENTARGUMENT"];
    // argument is the second argument of the __doPostBack function.
  }
}

The Form key __EVENTTARGET holds the ClientID of the UpdatePanel, similar to the AsyncPostBackSourceElementID

The Form key __EVENTARGUMENT holds the second argument of the __doPostBack function. When the __doPostBack function is called with only one argument, the value in __EVENTARGUMENT can be something like “undefined”. This depends on the browser. I recommend to send an empty string as second argument when no data is required for the request.

Check my follow up post here