When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, September 8, 2010

Building Interactive User Interfaces with Microsoft ASP.NET AJAX: Rebinding Client-Side Events After a Partial Page Postback

By Scott Mitchell


A Multipart Series on ASP.NET AJAX
Over the past several years web developers have started using JavaScript to make asynchronous postbacks to the web server that only transmit and receive the necessary data; these techniques are commonly referred to as AJAX. Microsoft has released a free AJAX framework for ASP.NET developers named Microsoft ASP.NET AJAX. This article series examines using Microsoft's ASP.NET AJAX framework to build responsive user interfaces.

  • AJAX Basics and Getting Started with Microsoft's ASP.NET AJAX Framework - examines AJAX basics and looks at installing Microsoft ASP.NET AJAX; includes a demo of the UpdatePanel control.
  • Using the UpdatePanel - provides more in-depth and real-world examples of using the UpdatePanel.
  • Providing Visual Feedback with the UpdateProgress Control - shows how to use the UpdateProgress control to display visual feedback to the user when a partial page postback is in progress.
  • Performing Client Actions in Response to Partial Page Postbacks - learn how to execute client-side script in response to events raised by the partial page postback life-cycle.
  • Using the Timer Control - see how to asynchronously update a portion of the screen every n milliseconds.
  • Enabling Bookmarking and the Browser's Back Button - learn how to add history points to an AJAX-enabled web page so that your visitors can use their browsers' Back and Forward buttons and bookmarks.
  • Retrieving Server-Side Data Using Web Services - call Web Services from an ASP.NET AJAX application with a sprinkle of JavaScript.
  • A Look at JSON Serialization - explore the serialization format used by the ASP.NET AJAX Framework when calling Web Services from client-side script.
  • Triggering Full Page Postbacks From An UpdatePanel - learn how to override an UpdatePanel's default behavior and trigger a full page postback.
  • Refreshing An UpdatePanel With JavaScript - see how to refresh the contents of an UpdatePanel via JavaScript.
  • Rebinding Client-Side Events After a Partial Page Postback - discover how to automatically rebind client-side event handlers to HTML elements in an UpdatePanel after a partial page postback.
  • (Subscribe to this Article Series! )

    Introduction


    The UpdatePanel is the workhorse of the ASP.NET Ajax library. It is responsible for defining regions of a web page that trigger partial page postbacks (as opposed to full page postbacks). Such partial page postbacks transfer less information between the client and server and have their user interfaces updated seamlessly, thereby leading to a more interactive user experience. (For more information on UpdatePanels, refer to Using the UpdatePanel.) One side-effect of a partial page postback is that the HTML elements within the UpdatePanel are replaced with the markup returned on postback. This behavior is not noticeable and is not an issue unless you have client-side event handlers wired up to the elements within the UpdatePanel. Such client-side event handlers are lost after a partial page postback.

    Consider a very simple UpdatePanel that contains just a TextBox and a Button. Furthermore, assume we have JavaScript on the page that creates an event handler for the TextBox's focus and blur events, which "highlights" the TextBox when the user focuses it and unhighlights it when losing focus. Initially, this script works as expected - clicking on the TextBox will "highlight" it. However, things break down once the Button is clicked. When the Button is clicked the UpdatePanel triggers a partial page postback and submits an asynchronous HTTP request back to the server. The requested ASP.NET page then goes through its life-cycle again, but this time only the markup in the UpdatePanel (and the hidden form fields on the page) are returned to the browser. The UpdatePanel then overwrites its existing markup with the markup just returned from the server. Unfortunately, this overwriting obliterates the focus and blur client-side event handlers, meaning that selecting the TextBox no longer highlights it.

    In short, if there are client-side event handlers attached to HTML elements within an UpdatePanel it is imperative that they be rebound after a partial page postback. This article looks at three different ways to accomplish this. Read on to learn more!

    - continued -

    Exploring the Problem


    As noted in the introduction, client-side event handlers for HTML elements in an UpdatePanel are lost after a partial page postback. In this article we'll identify three different approaches for overcoming this obstacle, but before we do let me take a moment to explain the problem we are trying to solve in more detail to make sure we are all on the same page. (The code samples provided here are taken from a sample application I built, which you can download at the end of this article.)

    Imagine that you have a web page that uses a bit of JavaScript to highlight form fields like textboxes, drop-down lists, and checkboxes whenever a user selects the form field and removes the highlighting once focus has been lost. This functionality can be accomplished by adding the following JavaScript to your page's <head> section:

    <script type="text/javascript" src='<%=Page.ResolveClientUrl("~/Scripts/jquery-1.4.2.min.js") %>'></script>

    <script type="text/javascript">
       function HighlightFormField() {
          $(this).addClass('highlightFormField');
       }

       function UnhighlightFormField() {
          $(this).removeClass('highlightFormField');
       }

       $(document).ready(function() {
          $("input[type=text]").focus(HighlightFormField);
          $("select").focus(HighlightFormField);
          $("textarea").focus(HighlightFormField);

          $("input[type=text]").blur(UnhighlightFormField);
          $("select").blur(UnhighlightFormField);
          $("textarea").blur(UnhighlightFormField);
       });
    </script>

    The above script starts makes use of the jQuery library, which is a lightweight, cross-browser JavaScript library designed to ease JavaScript's most common tasks, including inspecting and manipulating the Document Object Model (DOM). Note that the first <script> element above starts by referencing the file where this library exists (~/Scripts/jquery-1.4.2.min.js). Next, the script defines two event handler functions named HighlightFormField and UnhighlightFormField, which add and remove the highlightFormField CSS class from the HTML element that raised the event. The $(document).ready event handler, which fires after the browser has loaded the DOM, wires up the all textboxes (input[type=text]), drop-down lists (select) and multi-line textboxes (textarea) focus and blur events to the HighlightFormField and UnhighlightFormField event handlers, respectively.

    With the above JavaScript in place, anytime a user selects a textbox or drop-down list it has the highlightFormField CSS class applied. The highlightFormField CSS class (not shown here) indicates a light-yellow background color and a dashed border. The screen shot below shows the page when visited through a browser and after clicking on the first textbox, which now appears highlighted.

    The first textbox is selected and, hence, appears highlighted.

    In the above user interface there is a DropDownList that asks the user if they want to receive the newsletter. If the user chooses Yes we might want to show a textbox to collect their email address. This could be done by adding a Panel to the page that contains a TextBox control to collect the email address.

    <asp:Panel runat="server" ID="pnlNewsletterFollowup" Visible="false">
       <p>
          <b>Your Email Address:</b>
          <asp:TextBox runat="server" ID="txtEmail" Columns="50"></asp:TextBox>
       </p>
    </asp:Panel>

    Next, the DropDownList control's AutoPostBack property would need to be set to True so that we could determine when the DropDownList was modified and display (or hide) the email Panel accordingly. We'd also create a server-side event handler for the DropDownList's SelectedIndexChanged event that would show or hide the Panel as needed.

    protected void ddlGetNewsletter_SelectedIndexChanged(object sender, EventArgs e)
    {
       if (ddlGetNewsletter.SelectedValue == "True")
          pnlNewsletterFollowup.Visible = true;
       else
          pnlNewsletterFollowup.Visible = false;
    }

    With the above modifications everything would continue to work as expected presuming that the user interface was not in an UpdatePanel. If changing the DropDownList's value caused a full postback to fire then changing the DropDownList would reload the entire page. On postback the $(document).ready event handler would execute and the client-side event handlers to highlight the form fields on the page would be established.

    However, if we put the above user interface within an UpdatePanel then things break down. When the page is first visited the $(document).ready event handler executes and creates the client-side event handlers - selecting a textbox highlights it as expected. But when the user makes a selection from the drop-down list there would be a partial page postback. On partial page postback, the UpdatePanel overwrites its existing markup with the markup returned from the server (which now includes the textbox for the user's email address), but doing so severs the client-side event handlers. Consequently, after a partial page postback the form fields are no longer highlighted upon selection.

    So how do we correct this behavior? In short, we need the client-side event handlers to be reestablished after the partial page postback completes. There are many ways this can be accomplished. Let's look at three such ways.

    Using the PageRequestManager Object's endRequest Event Handler


    In Performing Client Actions in Response to Partial Page Postbacks, a previous article in this series, we learned that whenever a partial page postback is triggered the PageRequestManager object manages the interaction, from dispatching the HTTP request back to the server to receiving to response and updating the user interface. During the life-cycle of a partial page postback, the PageRequestManager object performs the following client-side actions:
    1. The initializeRequest event is raised - this is the first event raised during the partial postback life-cycle and affords us an opportunity to determine the HTML element that triggered the postback and cancel the postback, if needed.
    2. The beginRequest event is raised - this event is raised just before the request is sent to the server. The UpdateProgress control uses this event to displayed it's output.
    3. The request is sent to the server and the page is re-rendered there.
    4. The pageLoading event is raised when the server returns its response.
    5. The pageLoaded event is raised. This event is raised whenever the content on the page is refreshed, be it via a full page postback or a partial page postback.
    6. The endRequest event is raised, signalling completion of the partial page postback lifecycle.
    Note the last step - the endRequest event is raised, signalling the completion of the partial page postback. After the partial page postback has completed the UpdatePanel's user interface has been overwritten and the client-side event handlers that were associated with the HTML elements in that user interface have been lost. This, then, is a great time to add those event handlers back in.

    To accomplish this we need to do two things:

    1. Move the code that adds the client-side event handlers to the page's textboxes and drop-down lists from the $(document).ready event handler to a new function (let's call it WireUpFormFields). We then need to call this new function from $(document).ready.
    2. Create an event handler for the PageRequestManager object's endRequest event that calls the WireUpFormFields function.
    Step 1 ensures adds the client-side event handlers to the form fields when the page is first loaded, while step 2 ensures that these client-side event handlers are added to the new user interface in the UpdatePanel once the partial page postback completes.

    Here's the updated <script> tag that goes in the <head> section. Note that the client-side event wiring code has been moved to a new function, WireUpFormFields, and that the $(document).ready event handler calls this function.

    <script type="text/javascript">
       ...

       function WireUpFormFields() {
          $("input[type=text]").focus(HighlightFormField);
          $("select").focus(HighlightFormField);
          $("textarea").focus(HighlightFormField);

          $("input[type=text]").blur(UnhighlightFormField);
          $("select").blur(UnhighlightFormField);
          $("textarea").blur(UnhighlightFormField);
       }

       $(document).ready(function() {
          WireUpFormFields();
       });
    </script>

    Next, we need to have the WireUpFormFields function called whenever the endRequest event fires. This code must appear after the ScriptManager control, so don't put it in the <head> section. Instead, add this <script> block at the end of the page (or anywhere else after the ScriptManager control).

    <script type="text/javascript">
       // Create the event handler for PageRequestManager.endRequest
       var prm = Sys.WebForms.PageRequestManager.getInstance();
       prm.add_endRequest(WireUpFormFields);
    </script>

    Using the UpdatePanel's Server-Side Load Event Handler


    As we just saw, when a partial page postback occurs a number of client-side events fire. There are also server-side events that fire. For example, on each request to the web page - whether its the initial visit, a partial page postback, or a full page postback - the UpdatePanels on the page have their Load events fire. We can create a server-side Load event handler that programmatically injects JavaScript that wires up the client-side event handlers for the controls in the UpdatePanel.

    The code for the UpdatePanel's Load event handler would look similar to the following. Note that I am using the ScriptManager object's RegisterStartupScript method to programmatically inject JavaScript into the page. In short, I'm saying, "Whenever the UpdatePanel is loaded, call the WireUpFormFields client-side function."

    protected void upDataEntry_Load(object sender, EventArgs e)
    {
       // Add client-side script to call the WireUpFormFields function
       ScriptManager.RegisterStartupScript(this, this.GetType(),
                      Guid.NewGuid().ToString(),
                      "WireUpFormFields();", true);
    }

    Using jQuery's live() Function


    If you are using jQuery, as I did in these examples, there's an even easier approach - the live() function. The live() function defines an event handler for one or more HTML elements now or in the future. What that means is that you can say things like, "Hey, jQuery, I want you to affix this event handler to the click event of any <a> element on the page, whether it exists now or at some future point." Consequently, if an <a> element is dynamically added to the page at a later time, jQuery will automatically wire up its click event to the specified event handler.

    For our purposes we want to wire up the HighlightFormField and UnhighlightFormField event handlers to the focus and blur events of the textboxes and drop-down lists on the page now or in the future. The "in the future" part ensures that after a partial page postback, when the original textboxes and drop-down list are replaced with new ones, those new form fields will automatically be configured to have the client-side event handlers we had initially defined when the page was first loaded.

    Using the live() function is pretty straightforward - just specify the event name (as a string) and the event handler, as the following script shows:

    <script type="text/javascript">
       ...

       $(document).ready(function() {
          $("input[type=text]").live('focus', HighlightFormField);
          $("select").live('focus', HighlightFormField);
          $("textarea").live('focus', HighlightFormField);

          $("input[type=text]").live('blur', UnhighlightFormField);
          $("select").live('blur', UnhighlightFormField);
          $("textarea").live('blur', UnhighlightFormField);
       });
    </script>

    Using the live() function is probably the easiest and most intuitive approach, but it presumes that you are using jQuery. If you are not using jQuery you'll need to rely on one of the two other techniques covered in this article.

    Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the Demo Code Used in this Article

    Further Reading


  • Using the UpdatePanel
  • Performing Client Actions In Response to Partial Page Postbacks
  • jQuery $(document).ready and UpdatePanels?
  • $(document).ready() and pageLoad() are not the same!
  • A Multipart Series on ASP.NET AJAX
    Over the past several years web developers have started using JavaScript to make asynchronous postbacks to the web server that only transmit and receive the necessary data; these techniques are commonly referred to as AJAX. Microsoft has released a free AJAX framework for ASP.NET developers named Microsoft ASP.NET AJAX. This article series examines using Microsoft's ASP.NET AJAX framework to build responsive user interfaces.

  • AJAX Basics and Getting Started with Microsoft's ASP.NET AJAX Framework - examines AJAX basics and looks at installing Microsoft ASP.NET AJAX; includes a demo of the UpdatePanel control.
  • Using the UpdatePanel - provides more in-depth and real-world examples of using the UpdatePanel.
  • Providing Visual Feedback with the UpdateProgress Control - shows how to use the UpdateProgress control to display visual feedback to the user when a partial page postback is in progress.
  • Performing Client Actions in Response to Partial Page Postbacks - learn how to execute client-side script in response to events raised by the partial page postback life-cycle.
  • Using the Timer Control - see how to asynchronously update a portion of the screen every n milliseconds.
  • Enabling Bookmarking and the Browser's Back Button - learn how to add history points to an AJAX-enabled web page so that your visitors can use their browsers' Back and Forward buttons and bookmarks.
  • Retrieving Server-Side Data Using Web Services - call Web Services from an ASP.NET AJAX application with a sprinkle of JavaScript.
  • A Look at JSON Serialization - explore the serialization format used by the ASP.NET AJAX Framework when calling Web Services from client-side script.
  • Triggering Full Page Postbacks From An UpdatePanel - learn how to override an UpdatePanel's default behavior and trigger a full page postback.
  • Refreshing An UpdatePanel With JavaScript - see how to refresh the contents of an UpdatePanel via JavaScript.
  • Rebinding Client-Side Events After a Partial Page Postback - discover how to automatically rebind client-side event handlers to HTML elements in an UpdatePanel after a partial page postback.
  • (Subscribe to this Article Series! )



    ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article