Subtleties in Providing a Read-Only User InterfaceBy Scott Mitchell
A common pattern in data-driven Web applications is that of the read-only user interface. Often a website contains a page that displays records from a database that, by default, the visitor can edit. However, there are times when the data is not editable, and needs to be displayed in a read-only interface. Deciding whether or not to display the user interface in read-only mode can be dependent on any number of factors. Perhaps only certain users can edit the data, while others can only view it, or perhaps the data can only be edited by the person who added the particular information, or maybe there's some sort of expiration date, after which the data can no longer be edited.
Regardless of why the data may or may not be read-only, there are two general techniques that can be used to implement such
an interface on a single ASP.NET page. The prettiest, most intuitive way is to display textboxes, drop-down lists, checkboxes,
and so on for editable data and plain-text for read-only data. This approach, of course, takes a little bit of extra work
since for each input both an input Web control needs to be added to the page as well as a Label, and then the appropriate
control needs to be shown or hidden based on whether or not the data is editable. Most developers opt for a somewhat simpler
approach and use disabled or read-only textboxes, drop-down lists, and checkboxes. With this second approach, there's just
one user interface, but the developer sets the
ReadOnly properties of the Web controls
based on whether or not the data is editable.
When using the latter approach, there are certain subtleties that can creep up and lead to unexpected behavior due to the way browsers handle disabled form elements. In this article we'll discuss the differences between disabled and read-only controls and examine some of the subtleties that arise when creating read-only user interfaces, along with workarounds. Read on to learn more!
A Common Read-Only User Interface Pattern
Each ASP.NET Web control contains an
Enabledproperty that, if set to False, renders the control as disabled. A disabled control's HTML content contains the attribute
disabled="disabled", which causes the browser to make the resulting element inactive. The actual appearance varies by browser, but typically the text is grayed out and the control does not respond to user interaction.
When creating an ASP.NET page that needs to sometimes be editable and other times read-only, many developers simply create
the user interface for editing and then, if the data is read-only, programmatically set the
Enabled property to
False for all of those controls that constitute the data entry portion of the page. In my projects that use this pattern,
I typically define a
DisableControls(c) method in my
library of common functions (perhaps in a custom base
Page class) that disables the control c and all of the controls in the control hierarchy rooted at c.
DisableControls() method might look like:
Then, from my ASP.NET web page's code-behind class I can call this method. To disable all controls in the Web Form I
simply pass in the Web Form itself (
form1, by default), but more often than not I want to only disable a certain
subset of controls (the data entry-related ones), and have those in a Panel, which I can then pass in to this method.
In the ASP.NET
Page_Load event handler, then, my code looks something like:
Subtleties with Disabled Form Fields
One subtlety of disabled form fields that many developers aren't aware of is that, according to the official spec, a browser is not supposed to postback the values of disabled form fields. If you check out the W3C specification on HTML forms you'll find that there are two classes of form fields: "successful" form fields and form fields that are not "successful." A "successful" form field is one that's "valid" for submission, meaning that the form field's name and value are sent back to the web server when the form is submitted.
This subtlety can raise problems if you need to receive back the values of the Web controls in order to have your page process correctly. This sort of need arises when creating a form that uses client-side script to disable certain form fields based on user action. For example, imagine that, by default, a form's elements are editable, but if the user checks a "Lock Values" checkbox, the behavior is to disabled all form fields on the page. Or perhaps if the user selects a particular item from a drop-down list, another form field on the page becomes moot, and to illustrate this you decide to disable the form field using client-side script in such a scenario.
Since the value of these form fields that have been disabled on the client-side are not posted back to the server, the ASP.NET page assumes that the value is what it was on the previous page visit (which is either the value specified declaratively, or whatever's stored in view state). In other words, a user's changes to the form field will be lost if the form field is marked as disabled on the client-side.
To illustrate this, consider the following example: an ASP.NET page that displays a particular customer's address, along with an ability to lock the record. If the visitor clicks the Lock checkbox, the form fields are disabled using client-side script. The problem is that if the user makes any changes to the form field values before checking the Lock checkbox, these changes are lost because the disabled form fields' values are not posted back to the web server. The download at the end of this article includes a demo illustrating this problem; you can also check out this live demo.
To toggle the disabled status of an HTML element on the page, simply call
where id is the value of the HTML element's
id attribute. In the live demo, this client-side function is
called, passing in the
ids of the three textboxes, whenever the "Lock" checkbox is clicked.
The problem illustrated by the live demo is due because disabled HTML elements do not postback their values on form submission. There are two ways to fix this: using client-side script to "faux" disable a control, and using client-side script to make disabled controls enabled immediately before submitting the form. Let's examine both of these potential workarounds.
|Why Not Use the |
The ASP.NET TextBox Web control provides a
Fixing the Disabled Form Fields Problem By Using a "Faux" Disabled State
toggleInputElementsDisabledStatus()function to use the following code:
onfocus event. If it does, then we assume that the control is "faux disabled." To "enable" it
we clear the element's
onfocus event handler out and set the background color to white. If it does not have an
event handler for its
onfocus event, we assume that is is "enabled" and therefore make it "faux disabled" by
setting the background color to gray and set its
handler to a function that immediately removes focus when the control receives focus.
This behavior mimics the functionality of disabled controls, but since the controls are really still enabled, they submit on postback, thereby eliminating the problem identified earlier.
Fixing the Disabled Form Fields Problem Using ASP.NET 2.0's
SubmitDisabledControlsproperty to Web Forms. By setting this property to True, the
<form>element emitted to the page includes an
onsubmitevent handler that calls the
To set the
SubmitDisabledControls property to True, simply add it to the
tag in your ASP.NET web page, like so:
Keep in mind, this property is new to ASP.NET 2.0, and therefore won't produce the expected results in ASP.NET 1.x.
The live demo examined earlier, along with the two workarounds, are available for download at the end of this article.