Disabling a User Interface Element During a Partial Page PostbackBy Scott Mitchell
When using Microsoft's ASP.NET AJAX framework and an UpdatePanel whose
ChildrenAsTriggersis set to True (the default), anytime a user interface element within the UpdatePanel would normally cause a full page postback, a partial page postback is performed instead. For example, clicking a Button Web control or selecting a different item from a DropDownList control whose
AutoPostBackproperty is set to True normally causes a full page postback, but if these controls are within an UpdatePanel, a partial page postback occurs instead. But what happens if a partial page postback is taking a while to complete and the user triggers the partial page postback again? Or what if during this lull she clicks some other Button in the same UpdatePanel, thereby causing a second partial page postback to ensue?
If a partial page postback is made from the same UpdatePanel while a partial page postback is ongoing, the first partial page postback is aborted and the second postback commences. Aborting a partial page postback simply means that the ASP.NET AJAX framework on the browser no long listens for a response back from the server for that request. It does not stop processing on the server, or rollback any state changes that may have occurred on the server. Consequently, if on a partial page postback you are inserting records into a database or making some other state change, if a user clicks a Button in an UpdatePanel to instigate a partial page postback, but then clicks the same Button again while the partial page postback is still ongoing, there will be two duplicate records inserted in the database.
There are a couple of ways to prevent the user from resubmitting a partial page postback while it's still ongoing. The most effective way, in my opinion,
is to "freeze" the frame by overlaying the screen with a
<div> element. (See the final demo in the article,
Providing Visual Feedback with the UpdateProgress Control.) Another option is
to disable the user interface element that triggered the postback during the partial page postback lifecycle. This prevents the user from resubmitting
the partial page postback. Read on to learn more!
The Need for Disabling the User Interface During a Partial Page Postback
The download available at the end of this article includes a demo named
NoDisabling.aspxthat illustrates the default behavior. The demo consists of an UpdatePanel control containing two Button Web controls. On the first page load, a Session variable named
NumberOfClicksis set to 0:
In the Buttons'
Click event handlers this Session variable is incremented and the Button that was clicked along with the value of the
Session variable are displayed in the
Results Label control. What's more, both Click event handlers sleep for five seconds to add an artifical
delay in the partial page postback. This delay is present to mimic the time it might take to perform the partial page postback in a real-world setting.
Click event handler for
A recent article of mine, Performing Client Actions in Response to Partial Page Postbacks,
showed how to execute client script at various stages during the partial page postback's lifecycle. If you haven't yet read this article, please do so before
continuing here. In the article I showed how to build a client-side event logger that displays a message as each client-side event of the
PageRequestManager object is raised. The demo available for download includes such functionality.
To see the need for disabling the user interface during a partial page postback, visit the demo page through a browser. Click the first button to instigate a partial page postback. The event log dislays two entries:
endRequest, is not displayed until the response is returned from the server (or if the partial page postback is aborted). During the partial page postback, click the first button again. This starts the second partial page postback. In the first stage of the second partial page postback (
initializeRequest), the first partial page postback is aborted. This behavior is evidenced by the event log in the screen shot below. Note that the first two events,
beginRequest, occurred at 11:08:14, and were triggered by clicking "Button 1" for the first time. Two seconds later, I clicked "Button 1" again. This triggered the third event log entry,
initializeRequest, at 11:08:16. Because the first postback is still outstanding, it is automatically aborted. The fourth event log entry,
endRequest, indicates the conclusion of the first partial page postback. And the fifth event log entry (
beginRequest) signals the second stage of the second partial page postback.
What's important to understand is that aborting a postback causes the client API to stop listening for a response, but it does not stop processing on the server
or rollback any state changes. This is made clear by the output displayed in the
Results Label at the conclusion of the second partial page
postback. Even though the first partial page postback was aborted, the Session variable has been incremented twice.
In cases where the partial page postback performs some sort of state modification it is prudent to prevent the user from re-triggering the partial page postback when the partial page postback is ongoing. This article examines one approach for accomplishing this functionality: by disabling the user interface element that caused the partial page postback.
Determining the User Interface Element that Triggered the Partial Page Postback and Disabling It
As we've already seen, whenever a partial page postback commences, the
PageRequestManagerraises a series of client-side events. The first one is
initializeRequest. Following that, the
beginRequestevent is raised. The
beginRequestis passed an
argsobject that includes information on what user interface element caused the partial page postback. Specifically, this information can be retrieved via
args.get_postBackElement(). Once we have a reference to the user interface element that caused the postback, we can disable it by setting its
This code disables the user interface element at the start of the partial page postback (before the actual HTTP request is transmitted from the client to the server). However, this code alone is not sufficient - we need to enable the user interface element once the partial page postback completes.
Re-Enabling the User Interface Element that Triggered the Partial Page Postback
endRequestevent at the conclusion of a partial page postback, regardless of whether the partial page postback completed successfully, ended from an error, or was canceled or aborted from client-side script or by user action. Therefore, it makes sense to re-enable the user interface element in the
endRequest event handler is not passed a reference to the control that triggered the partial page postback.
uiId. This variable is assigned the
id attribute of the element that caused the partial page postback in the
beginRequest event handler. It is then used in the
endRequest event handler to get a reference to the element and set its
disabled property to
Note that in the
endRequest event handler I use the
function to get a programmatic reference to the element specified by the ID value
$get(id) is a function that
is part of the ASP.NET AJAX framework's client API. It serves as a shortcut to the
Testing the Disabled UI Functionality
The download available at the end of this article includes a demo named
Disabling.aspxthat has the same user interface as
NoDisabling.aspx, but implements the client-side disabling/enabling logic we just discussed. The following screen shot shows the page shortly after "Button 1" has been clicked. Note that "Button 1" is disabled - it does not respond to clicks until it is re-enabled.
After the partial page postback completes, "Button 1" is re-enabled and can be clicked again to perform another partial page postback.
Stopping Other Partial Page Postbacks
Disabling the user interface element that triggers the partial page postback ensures that the same control won't initiate another postback, thereby aborting its ongoing request. But what if another element in the same UpdatePanel triggers a partial page postback? For example, what happens if, in the
Disabling.aspxdemo, the user clicks "Button 1" and then, during the postback, clicks "Button 2"? Clicking "Button 2" aborts the "Button 1" postback and then initiates the "Button 2" partial page postback logic.
To prevent this we can either disable the entire user interface in the event of a partial page postback (instead of just "Button 1"). See the final demo in the Providing Visual Feedback with the UpdateProgress Control article for such an example. Another option is to programmatically prevent a partial page postback from starting if there is an ongoing one.
sender object passed into the
initializeRequest event handler has a function named
that returns a Boolean value indiciating if there is an ongoing partial page postback. To permit only one partial page postback at a time, check this
function and cancel the current request if it returns
In addition to canceling the requested partial page postback, the above code also displays an alert explaining to the user that their current request cannot be processed until the ongoing request finishes. The following screen shot shows this functionality in action. "Button 1" has been clicked and is in the midst of a partial page postback. Because of the script we added in the previous section, the button is disabled. If the user clicks "Button 2" during the partial page postback, an alert box is shown and the partial page postback request from "Button 2" is canceled.
In some circumstances, a partial page postback performs some action on the server that affects the state of the web application. For such partial page postbacks it's usually important that the user does not repeatedly cause the same partial page postback. For example, if the partial page postback inserts a record into the database, triggering the same partial page postback multiple times - by, say, clicking a Button repeatedly - may result in duplicate database entries. To remedy this you can either disable the entire user interface by means of an overlaid
<div>element or you can more selectively disable the user interface element that triggered the partial page postback for the duration of the postback. This article examined the latter approach.