Building Interactive User Interfaces with Microsoft ASP.NET AJAX: Performing Client Actions in Response to Partial Page Postbacks
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.
Introduction
The previous three articles in this series focused on building AJAX-enabled web applications using server-side techniques and controls. For instance,
Using the UpdatePanel examined how to define regions on the page that participate
and are updated by partial page postbacks; Providing Visual Feedback with the UpdateProgress
Control showed how to use the UpdateProgress control to display feedback during a long-running partial page postback.
The ASP.NET AJAX Framework also includes a rich client-side library and event model that enables page developers to create and execute client script
and event handlers that integrate with the ASP.NET AJAX Framework. This article starts our examination of client-side development with the ASP.NET AJAX
Framework. In particular, it examines the client-side PageRequestManager object, which includes methods and events tied to the partial page
postback mechanism. In a nutshell, we can use the PageRequestManager object to execute client-side script immediately before or after a partial
page postback.
This article discusses the basics of the client-side PageRequestManager object and includes examples that show how to abort and cancel partial page postbacks
as well as how to scroll to a particular location on screen after a partial page postback completes. These working demos are available for download at the end of
this article. Read on to learn more!
The Client-Side Events of a Partial Page Postback
As discussed in Using the UpdatePanel, whenever a Web control within an UpdatePanel causes a postback -
such as a Button Web control being clicked - instead of a regular postback the UpdatePanel performs a partial page postback. A partial page postback asynchronously
communicates with the web server and sends the page's form field values. On the server, the page is re-rendered but only the HTML content for the appropriate UpdatePanel regions
are returned to the browser. These regions are then dynamically updated. All of this hard work is handled for us by the client- and server-side pieces of the ASP.NET AJAX
Framework.
Our jobs as page developers are simple: just add an UpdatePanel control to the page and all that magical AJAXy goodness happens automatically. But what happens
if we need more control over the partial postback life-cycle? For example, imagine that we need to execute some client-side script after the partial page postback completes?
Or what if we want to cancel the partial page postback if some condition is true? The good news is that such custom functionality is available. We can create client-side event
handlers that execute in response to certain events during the life-cycle of a partial page postback.
The partial page postback is managed on the client-side by the PageRequestManager object.
Whenever a partial page postback is initiated, the PageRequestManager object performs the following client-side actions:
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.
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.
The request is sent to the server and the page is re-rendered there.
The pageLoading event is raised when the server returns its response.
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.
The endRequest event is raised, signalling completion of the partial page postback
lifecycle.
Keep in mind that these are client-side events. These events are being raised on the user's web browser. We can tap into these events by writing JavaScript that wires
an event handler to one of these events.
"Viewing" the Events Raised During the Partial Page Postback Life-cycle
To better understand the stages of the partial page postback life-cycle, I've created a very demo with a Button in an UpdatePanel. When this Button is clicked, a partial page
postback begins. I've also added client-side script that displays a message on screen as each of these events fires. Here's a boiled down version of this page's declarative
markup:
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
<ProgressTemplate>
<span style="color:Red;font-size:larger;">PERFORMING POSTBACK... THIS WILL TAKE FIVE SECONDS....</span>
</ProgressTemplate>
</asp:UpdateProgress>
<div id="logOutput"></div>
There are four key elements in the declarative markup:
The ScriptManager control. As discussed in previous installments of this article series, the ScriptManager is the "engine" that is needed in every AJAX-enabled web page.
The UpdatePanel control. This UpdatePanel includes a solitary Button control (PartialPostbackButton) that, when clicked, performs a partial page postback.
I also have created a server-side event handler for this Button control that executes the code Thread.Sleep(5000), putting the thread to sleep for five seconds.
This adds an artificial delay to the page so as to better illustrate what PageRequestManager object events fire before the request to the server and afterwards.
The UpdateProgress control. Displays a message during the five second delay on the server.
A <div> element with idlogOutput. We will add JavaScript in a moment that logs messages to this element during execution of the
various PageRequestManager event handlers.
In addition to this markup, the demo page also includes the following JavaScript. (Note: when adding JavaScript that utilizes the ASP.NET AJAX Framework you can either add it
directly within the ASP.NET page or as an external script file. This demo has the JavaScript content directly in the page. When adding script directly to the page it is vital
that it appears after the ScriptManager control.)
<script type="text/javascript">
// Create the event handlers for PageRequestManager
var prm = Sys.WebForms.PageRequestManager.getInstance();
function PageRequestManager_initializeRequest(sender, args) {
logEvent("initializeRequest");
}
function PageRequestManager_beginRequest(sender, args) {
logEvent("beginRequest");
}
function PageRequestManager_pageLoading(sender, args) {
logEvent("pageLoading");
}
function PageRequestManager_pageLoaded(sender, args) {
logEvent("pageLoaded");
}
function PageRequestManager_endRequest(sender, args) {
logEvent("endRequest");
}
var count = 1;
function logEvent(msg) {
var logOutput = document.getElementById('logOutput');
var rightNow = new Date();
logOutput.innerHTML += '(' + count + ') ' + msg + ' (' + rightNow.toTimeString() + ')<br />';
count++;
}
</script>
The first line of code gets an instance of the PageRequestManager object. Next, the five PageRequestManager object events are wired up to
five event handlers. Each of the five event handlers call the logEvent function, passing in a message to display. The logEvent function
updates the logOutput<div>'s innerHTML, appending the message and current time.
The three screenshots below show this demo in action. The first screenshot shows the page when it is first loaded. Note that the log output already contains one entry for
the pageLoaded event. As noted earlier, the PageRequestManager object's pageLoaded event is raised whenever the page's contents have
been refreshed whether we are dealing with a full page postback (such as when the page is first visited or when a control outside of an UpdatePanel causes a postback) or a
partial page postback.
The second screenshot shows the page after the "Perform a Partial Postback" button has been clicked but before the server returns with its response. Note that the
UpdateProgress control is showing its message (the text in red). Also, two new client-side event handlers have fired: initializeRequest
and beginRequest.
When the response is returned from the web server the remaining PageRequestManager object events fire: pageLoading, pageLoaded, and
endRequest. Here you see that the response has returned from the server: the UpdateProgress control is no longer displayed and the event log lists the
pageLoading, pageLoaded, and endRequest events. Notice that the pageLoading event was raised five seconds after
beginRequest. This is because the server-side code that executes when the "Perform a Partial Postback" button is clicked sleeps for five seconds.
Aborting and Canceling Partial Page Postbacks
The PageRequestManager object's initializeRequest event offers page developers an opportunity to cancel the postback, if needed.
Furthermore, the PageRequestManager object includes a function that, when executed, aborts all partial page postbacks, both those that are in progress and those
that are queued up. To illustrate aborting and canceling postbacks, I created a demo similar to the one we just examined. In addition to the Button control, I added a Label in the
UpdatePanel that displays the time the UpdatePanel was updated. Outside of the UpdatePanel I added two controls used for demoing the abort and cancel features:
A CheckBox control named CancelThisPostback that, if checked, causes the partial page postback to be canceled, and
A button that, when clicked, aborts all outstanding postbacks.
The page contains JavaScript similar to the previous example, as well. I've updated the client-side PageRequestManager_initializeRequest event handler, however,
to cancel the partial page postback if the CancelThisPostback checkbox is checked:
function PageRequestManager_initializeRequest(sender, args) {
logEvent("initializeRequest");
// See if we need to cancel this postback
var cb = document.getElementById('<%=CancelThisPostback.ClientID%>');
if (cb.checked) {
// Cancel this postback request
args.set_cancel(true);
logEvent("Postback canceled");
}
}
If the checkbox CancelThisPostback is checked the partial page postback is canceled by calling args.set_cancel(true); and a message is added to the
log indicating that the postback was canceled. To test out this functionality, visit the page and click the "Perform a Partial Postback" button. As before, the page progresses through the various steps and the output is displayed
in the client-side event handler log. Also, the time in the UpdatePanel is updated to the current time. Now, check the "Cancel this postback" checkbox and click the
"Perform a Partial Postback" button. This time no partial page postback occurs.
The following screenshot shows the output of the page when the "Cancel this postback" checkbox is checked. Note that the client-side event handler log has just three entries:
pageLoaded - this was displayed when the page was first loaded
initializeRequest - this was displayed when the "Perform a Partial Postback" button was clicked, thereby starting the partial postback life-cycle
Postback canceled - the postback was canceled.
This approach allows you to cancel the current partial page postback from the initializeRequest event handler. The ASP.NET AJAX Framework also allows you
to abort all outstanding partial page postback requests. To accomplish this call the PageRequestManager object's abortPostBack() function.
To demo using this functionality, I created the following client-side function, which is executed whenever the "Abort Outstanding Partial Page Postbacks" button is clicked.
function AbortAllPostbacks() {
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.abortPostBack();
logEvent("Partial page postbacks aborted");
}
To test this functionality, visit the demo page and click the "Perform a Partial Postback" button (with the "Cancel this postback" checkbox unchecked). This will start the
partial page postback life-cycle. After the UpdateProgress output appears, click the "Abort Outstanding Partial Page Postbacks." This will abort the current partial page postback
and immediately raise its endRequest event. The following screenshot shows the client-side event handler log when the "Abort Outstanding Partial Page Postbacks"
button is clicked during a partial page postback. As you can see, the partial page postback started normally as its initializeRequest and beginRequest
events were raised, but during the processing on the server the postback was aborted. This caused the endRequest event to be raised immediately.
Scrolling the Browser Window to a Particular HTML Element When the Partial Page Postback Completes
I was recently working with a colleague who was using AJAX in a database search page. Essentially, users would enter various filtering criteria into TextBox controls,
click a "Show Results" button, and the results would be displayed in a sortable and pageable GridView beneath the TextBox controls. The TextBoxes and GridView were both in
an UpdatePanel.
The page was laid out such that the "Show Results" button was at the bottom of the browser screen for users with low screen resolutions. After typing in search values into the
TextBox controls and clicking the "Show Results" button, the GridView would be populated beneath the "Show Results" button, but these users would not see the results because they
were "beneath the fold." In short, they needed to scroll down to see the results. But because AJAX provides such a smooth user experience, the users didn't realize that the page
had been updated. There was no "flash" of the screen or other cue that their action - clicking the "Show Results" button - had done anything because the actual output was
displayed further down on the page.
The solution was to automatically scroll the user's browser to a particular HTML element situated directly above the output. This scrolling needed to occur whenever the partial
page postback concluded.
The browser's window object includes a scrollTo(x, y) method that will scroll to a particular (x,y) coordinate. With a little bit of
script it's possible to determine the (x,y) coordinate of an HTML element. We found a script
created by Eric Pascarello that packaged up this functionality into a JavaScript function named ScrollToElement(element). We then called this method
passing in the HTML element to scroll to in the endRequest event handler.
function PageRequestManager_endRequest(sender, args) {
// Scroll to the specified HTML element
var scrollTo = document.getElementById('scrollHere');
ScrollToElement(scrollTo);
}
The scrollHere passed into the getElementById(id) function references a <div> element on the page located above the
category drop-down list.
Check out the demos available for download at the end of this article to see this functionality in action. The two screenshots below provide a glimpse at its behavior. The
first screenshot shows the page when it is first viewed. At the bottom of the fold is a drop-down list where the user can select a category. Once they've selected a category
and clicked the "Display Matching Products" button a GridView is displayed beneath the drop-down list that lists those products that belong to the selected category.
By default, after clicking the "Display Matching Products" button the user's browser window would stay fixed in its current location. A user would have to manually scroll down
to see the results and, if by chance the "Display Matching Products" button was already at the bottom of their browser window they might not realize that the report the requested
was available further down on the screen.
With the script added to this page, the user's browser is automatically scrolled to show the results when the partial page postback completes.
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.