Adding Validation Controls to the DataList’s Editing Interface
In the DataList editing tutorials thus far, the DataLists’ editing interfaces have not included any proactive user input validation even though invalid user input — such as a missing product name or negative price — results in an exception. In the preceding tutorial we examined how to add exception handling code to the DataList’s UpdateCommand
event handler in order to catch and gracefully display information about any exceptions that were raised. Ideally, however, the editing interface would include validation controls to prevent a user from entering such invalid data in the first place.
In this tutorial we’ll see how easy it is to add validation controls to the DataList’s EditItemTemplate
in order to provide a more foolproof editing user interface. Specifically, this tutorial takes the example created in the preceding tutorial and augments the editing interface to include appropriate validation.
In the Handling BLL- and DAL-Level Exceptions tutorial we created a page that listed the names and prices of the products in a two-column, editable DataList. Our goal for this tutorial is to augment the DataList’s editing interface to include validation controls. In particular, our validation logic will:
- Require that the product’s name be provided
- Ensure that the value entered for the price is a valid currency format
- Ensure that the value entered for the price is greater than or equal to zero, since a negative
UnitPrice
value is illegal
Before we can look at augmenting the previous example to include validation, we first need to replicate the example from the ErrorHandling.aspx
page in the EditDeleteDataList
folder to the page for this tutorial, UIValidation.aspx
. To achieve this we need to copy over both the ErrorHandling.aspx
page’s declarative markup and its source code. First copy over the declarative markup by performing the following steps:
- Open the
ErrorHandling.aspx
page in Visual Studio
- Go to the page’s declarative markup (click on the Source button at the bottom of the page)
- Copy the text within the
<asp:Content>
and </asp:Content>
tags (lines 3 through 32), as shown in Figure 1.
- Open the
UIValidation.aspx
page
- Go to the page’s declarative markup
- Paste the text within the
<asp:Content>
control.
To copy over the source code, open the ErrorHandling.aspx.vb
page and copy just the text within the EditDeleteDataList_ErrorHandling
class. Copy the three event handlers (Products_EditCommand
, Products_CancelCommand
, and Products_UpdateCommand
) along with the DisplayExceptionDetails
method, but do not copy the class declaration or using
statements. Paste the copied text within the EditDeleteDataList_UIValidation
class in UIValidation.aspx.vb
.
After moving over the content and code from ErrorHandling.aspx
to UIValidation.aspx
, take a moment to test out the pages in a browser. You should see the same output and experience the same functionality in each of these two pages (see Figure 2).
Step 2: Adding the Validation Controls to the DataList’s EditItemTemplate
When constructing data entry forms, it is important that users enter any required fields and that all their provided inputs are legal, properly-formatted values. To help ensure that a user’s inputs are valid, ASP.NET provides five built-in validation controls that are designed to validate the value of a single input Web control:
For more information on these five controls refer back to the Adding Validation Controls to the Editing and Inserting Interfaces tutorial or check out the Validation Controls section of the ASP.NET Quickstart Tutorials.
For our tutorial we’ll need to use a RequiredFieldValidator to ensure that a value for the product name has been supplied and a CompareValidator to ensure that the entered price has a value greater than or equal to 0 and is presented in a valid currency format.
Note: While ASP.NET 1.x had these same five validation controls, ASP.NET 2.0 has added a number of improvements, the main two being client-side script support for browsers in addition to Internet Explorer and the ability to partition validation controls on a page into validation groups. For more information on the new validation control features in 2.0, refer to Dissecting the Validation Controls in ASP.NET 2.0.
Let’s start by adding the necessary validation controls to the DataList’s EditItemTemplate
. This task can be performed through the Designer by clicking on the Edit Templates link from the DataList’s smart tag, or through the declarative syntax. Let’s step through the process using the Edit Templates option from the Design view. After choosing to edit the DataList’s EditItemTemplate
, add a RequiredFieldValidator by dragging it from the Toolbox into the template editing interface, placing it after the ProductName
TextBox.
All validation controls work by validating the input of a single ASP.NET Web control. Therefore, we need to indicate that the RequiredFieldValidator we just added should validate against the ProductName
TextBox; this is done by setting the validation control’s ControlToValidate
property to the ID
of the appropriate Web control (ProductName
, in this instance). Next, set the ErrorMessage
property to “You must provide the product’s name” and the Text
property to “*”. The Text
property value, if provided, is the text that is displayed by the validation control if the validation fails. The ErrorMessage
property value, which is required, is used by the ValidationSummary control; if the Text
property value is omitted, the ErrorMessage
property value is displayed by the validation control on invalid input.
After setting these three properties of the RequiredFieldValidator, your screen should look similar to Figure 4.
With the RequiredFieldValidator added to the EditItemTemplate
, all that remains is to add the necessary validation for the product’s price TextBox. Since the UnitPrice
is optional when editing a record, we don’t need to add a RequiredFieldValidator. We do, however, need to add a CompareValidator to ensure that the UnitPrice
, if supplied, is properly formatted as a currency and is greater than or equal to 0.
Add the CompareValidator into the EditItemTemplate
and set its ControlToValidate
property to UnitPrice
, its ErrorMessage
property to “The price must be greater than or equal to zero and cannot include the currency symbol”, and its Text
property to “*”. To indicate that the UnitPrice
value must be greater than or equal to 0, set the CompareValidator’s Operator
property to GreaterThanEqual
, its ValueToCompare
property to “0”, and its Type
property to Currency
.
After adding these two validation controls, the DataList’s EditItemTemplate
’s declarative syntax should look similar to the following:
<EditItemTemplate> Product name: <asp:TextBox ID="ProductName" runat="server" Text='<%# Eval("ProductName") %>'></asp:TextBox> <asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="ProductName" ErrorMessage="You must provide the product's name" runat="server">*</asp:RequiredFieldValidator> <br /> Price: <asp:TextBox ID="UnitPrice" runat="server" Text='<%# Eval("UnitPrice", "{0:C}") %>'></asp:TextBox> <asp:CompareValidator ID="CompareValidator1" ControlToValidate="UnitPrice" ErrorMessage="The price must be greater than or equal to zero and cannot include the currency symbol" Operator="GreaterThanEqual" Type="Currency" ValueToCompare="0" runat="server">*</asp:CompareValidator><br /> <br /> <asp:Button ID="UpdateProduct" runat="server" CommandName="Update" Text="Update" /> <asp:Button ID="CancelUpdate" runat="server" CommandName="Cancel" Text="Cancel" /> </EditItemTemplate>
After making these changes, open the page in a browser. If you attempt to omit the name or enter an invalid price value when editing a product, an asterisk appears next to the textbox. As Figure 5 shows, a price value that includes the currency symbol — such as $19.95 — is considered invalid. The CompareValidator’s Currency
Type
allows for digit separators (such as commas or periods, depending on the culture settings) and a leading plus or minus sign, but does not permit a currency symbol. This behavior may perplex users as the editing interface currently renders the UnitPrice
using the currency format.
While the validation works as-is, the user has to manually remove the currency symbol when editing a record, which is not acceptable. Moreover, if there are invalid inputs in the editing interface neither the Update nor Cancel buttons, when clicked, will invoke a postback. Ideally, the Cancel button would return the DataList to its pre-editing state regardless of the validity of the user’s inputs. Also, we need to ensure that the page’s data is valid before updating the product information in the DataList’s UpdateCommand
event handler, as the validation controls’ client-side logic can be bypassed by users whose browsers either don’t support JavaScript or have its support disabled.
Removing the Currency Symbol from the EditItemTemplate’s UnitPrice TextBox
When using the CompareValidator’s Currency
Type
, the input being validated must not include any currency symbols. The presence of such symbols causes the CompareValidator to mark the input as invalid. However, our editing interface currently includes a currency symbol in the UnitPrice
TextBox, meaning the user must explicitly remove the currency symbol before saving their changes. To remedy this we have three options:
- Configure the
EditItemTemplate
so that the UnitPrice
TextBox value is not formatted as a currency.
- Allow the user to enter a currency symbol by removing the CompareValidator and replacing it with a RegularExpressionValidator that checks for a properly formatted currency value. The challenge here is that the regular expression to validate a currency value is not as straightforward as the CompareValidator and would require writing code if we wanted to incorporate culture settings.
- Remove the validation control altogether and rely on custom server-side validation logic in the GridView’s
RowUpdating
event handler.
Let’s go with option 1 for this tutorial. Currently the UnitPrice
is formatted as a currency value due to the databinding expression for the TextBox in the EditItemTemplate
: <%# Eval("UnitPrice", "{0:c}") %>
. Change the Eval
statement to Eval("UnitPrice", "{0:n2}")
, which formats the result as a number with two digits of precision. This can be done directly through the declarative syntax or by clicking on the Edit DataBindings link from the UnitPrice
TextBox in the DataList’s EditItemTemplate
.
With this change, the formatted price in the editing interface includes commas as the group separator and a period as the decimal separator, but leaves off the currency symbol.
Note: When removing the currency format from the editable interface, I find it helpful to put the currency symbol as text outside the TextBox. This serves as a hint to the user that they do not need to provide the currency symbol.
Fixing the Cancel Button
By default, the validation Web controls emit JavaScript to perform validation on the client-side. When a Button, LinkButton, or ImageButton is clicked, the validation controls on the page are checked on the client-side before the postback occurs. If there is any invalid data, the postback is cancelled. For certain Buttons, though, the validity of the data might be immaterial; in such a case, having the postback cancelled due to invalid data is a nuisance.
The Cancel button is such an example. Imagine that a user enters invalid data, such as omitting the product’s name, and then decides she doesn’t want to save the product after all and hits the Cancel button. Currently, the Cancel button triggers the validation controls on the page, which report that the product name is missing and prevent the postback. Our user has to type some text into the ProductName
TextBox just to cancel out of the editing process.
Fortunately, the Button, LinkButton, and ImageButton have a CausesValidation
property that can indicate whether or not clicking the Button should initiate the validation logic (defaults to True
). Set the Cancel Button’s CausesValidation
property to False
.
Ensuring the Inputs are Valid in the UpdateCommand Event Handler
Due to the client-side script emitted by the validation controls, if a user enters invalid input the validation controls cancel any postbacks initiated by Button, LinkButton, or ImageButton controls whose CausesValidation
properties are True
(the default). However, if a user is visiting with an antiquated browser or one whose JavaScript support has been disabled, the client-side validation checks will not execute.
All of the ASP.NET validation controls repeat their validation logic immediately upon postback and report the overall validity of the page’s inputs via the Page.IsValid
property. However, the page flow is not interrupted or stopped in any way based on the value of Page.IsValid
. As developers, it is our responsibility to ensure that the Page.IsValid
property has a value of True
before proceeding with code that assumes valid input data.
If a user has JavaScript disabled, visits our page, edits a product, enters a price value of “Too expensive”, and clicks the Update button, the client-side validation will be bypassed and a postback will ensue. On postback, the ASP.NET page’s UpdateCommand
event handler executes and an exception is raised when attempting to parse “Too expensive” to a Decimal
. Since we have exception handling, such an exception will be handled gracefully, but we could prevent the invalid data from slipping through in the first place by only proceeding with the UpdateCommand
event handler if Page.IsValid
has a value of True
.
Add the following code to the start of the UpdateCommand
event handler, immediately before the Try
block:
if (!Page.IsValid) return;
With this addition, the product will attempt to be updated only if the submitted data is valid. Most users won’t be able to postback invalid data due to the validation controls’ client-side scripts, but users whose browsers don’t support JavaScript or that have JavaScript support disabled, can bypass the client-side checks and submit invalid data.
Note: The astute reader will recall that when updating data with the GridView, we didn’t need to explicitly check the Page.IsValid
property in our page’s code-behind class. This is because the GridView consults the Page.IsValid
property for us and only proceeds with the update only if it returns a value of True
.
Step 3: Summarizing Data Entry Problems
In addition to the five validation controls, ASP.NET includes the ValidationSummary control, which displays the ErrorMessage
s of those validation controls that detected invalid data. This summary data can be displayed as text on the web page or through a modal, client-side messagebox. Let’s enhance this tutorial to include a client-side messagebox summarizing any validation problems.
To accomplish this, drag a ValidationSummary control from the Toolbox onto the Designer. The location of the ValidationSummary control doesn’t really matter, since we’re going to configure it to only display the summary as a messagebox. After adding the control, set its ShowSummary
property to False
and its ShowMessageBox
property to True
. With this addition, any validation errors are summarized in a client-side messagebox (see Figure 6).
Summary
In this tutorial we saw how to reduce the likelihood of exceptions by using validation controls to proactively ensure that our users’ inputs are valid before attempting to use them in the updating workflow. ASP.NET provides five validation Web controls that are designed to inspect a particular Web control’s input and report back on the input’s validity. In this tutorial we used two of those five controls — the RequiredFieldValidator and the CompareValidator — to ensure that the product’s name was supplied and that the price had a currency format with a value greater than or equal to zero.
Adding validation controls to the DataList’s editing interface is as simple as dragging them onto the EditItemTemplate
from the Toolbox and setting a handful of properties. By default, the validation controls automatically emit client-side validation script; they also provide server-side validation on postback, storing the cumulative result in the Page.IsValid
property. To bypass the client-side validation when a Button, LinkButton, or ImageButton is clicked, set the button’s CausesValidation
property to False
. Also, before performing any tasks with the data submitted on postback, ensure that the Page.IsValid
property returns True
.
All of the DataList editing tutorials we’ve examined so far have had very simple editing interfaces — a TextBox for the product’s name and another for the price. The editing interface, however, can contain a mix of different Web controls, such as DropDownLists, Calendars, RadioButtons, CheckBoxes, and so on. In our next tutorial we’ll look at building an interface that uses a variety of Web controls.
Happy Programming!
About the Author
Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott works as an independent consultant, trainer, and writer. His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. He can be reached at mailto:mitchell@4GuysFromRolla.com or via his blog, which can be found at http://scottonwriting.net/.