n ASP.NET,
you can include validation controls that automatically check user input on a page.
While this is not a new function (it was available through JavaScript include files),
the implementation certainly is. You no longer have to worry about where to do validation
(on the server or client), nor do you have to worry about the client-side code.
It's all provided by means of using the five built-in validation controls: Regular
Expression, Required Field, Range, Comparison, and Custom.
Much has already been written about the use
of the validation controls, so I won't go into the functionality of each. For those
details, see Anthony Moore's articles "User
Input Validation in ASP+" and "ASP+
Validation In-Depth". Suffice it to say that it's fairly easy to include
the controls on your page; simply specify any parameters that are needed (the control
to validate, the regular expression to validate against, and so on), and let it
run. That is the beauty of the new controls. You don't have to worry about how they
are implemented, just that they are there and functioning.
However, by including those validation controls
on your page, you are implying that you want all of the user's input validated before
acting upon it. Even if this isn't the intended effect, you might find out that
it is easiest to include these controls to check all the input. In this article,
I will explain why you might want to disable those controls and how to do so. I
will show you how to disable controls for an entire page, how to disable them from
the server, and how to disable them in certain instances on both the client and
the server.
The Validation Process
The following is a simplified description of
the process that happens when a validation control is used on a page. - When a page containing validation controls is requested, the user's browser type
and version is evaluated to determine if client-side validation routines should
be used.
- If the browser supports client-side validation, the page loads with the appropriate
routines being called from the validation controls. This is handled through a JScript®
include file.
- When the user moves between controls on a client-side validated form after changing
a control's value, the validation events for the control that lost the focus are
fired and appropriate error messages (if any) are displayed.
- If the user generates a form submit on a client-side validated form, the entire
form is evaluated for any validation controls that are not valid. If even one control
is not valid, the form will not be submitted.
- When the form is posted back to the server through a postback event, it is evaluated
for validity on the server. This occurs even if the form was already evaluated on
the client.
- If any of the validation controls are found to be invalid through the server-side
check, the page is redisplayed with the appropriate error messages included.
- If the form passes all validation on both the server and client, the page processing
sequence continues with the event that triggered the postback firing.
As you can see, the validation can occur multiple
times on the client as well as on the server. This provides enough validation so
that if implemented properly, almost no erroneous data will be passed. At times,
however, you might want to circumvent this process. Let's see why.
Reasons to Disable Form Validation
While form validation is a great tool for making
sure that invalid or incorrectly formatted data is never acted upon, there are certain
situations in which you might want the data to pass through. One instance, as Anthony
Moore's ASP+ Validation article suggests, is when you leave the form by means of
a Cancel button. Frequently, when entering an order, updating an FAQ, or registering,
the user will want to back out of what they are doing. You can provide a link on
the page that navigates elsewhere, thereby discarding all of the entered data, but
for consistent design every Submit button should have a matching Cancel button.
Another example is a multipart form. Since you
can only have one server-side form (runat=server), you cannot divide the page into
multiple forms that will generate postback events. If you have a page that lists
FAQs at the top for editing, but at the bottom of the page you provide the means
to add a new FAQ, you do not want the errors in editing to prevent someone from
adding a new FAQ to the page.
The trick in these instances is to know when
to allow validation and when to prevent it.
Disabling Client-Side Validation on the Entire Form
An easy way to disable all client-side form
validation is to provide the clienttarget=downlevel attribute in the Page directive
at the top of your page. The directive looks like this: <%@ Page Language="VB" codebehind="MyPage1.vb" Inherits MyApp.MyPage1"
clienttarget=downlevel>
You need to be careful when you do this because it not only disables all client-side
validation, it also disables any other client-side server control functionality.
You can also disable client-side form validation for all validation controls by
setting the global page variable Page_PostIfValidationError to True.
The only time you would do either of these is
when you have included some validation controls through a common include for the
page or embedded them in a custom control. Alternately, you can opt not to include
the validation controls on the page.
You can disable all client-side form validation
using a number of different methods depending upon the type of control that the
user activates. For a regular HTML control, you can set the Page_ValidationActive
property to false. For example: <input type=button runat=server id=cmdCancel value="Cancel" onClick="Page_ValidationActive=false;"
onServerClick="cmdCancel_Click">
Please note that it is important to set the onServerClick event to equal the event
you have defined in the codebehind page for the control; otherwise, the event won't
fire since you have overridden the onClick event.
For a server-side control, disabling all form
validation requires some client-side code, like this: <asp:button runat=server id=cmdCancel Text="Cancel" onClick="cmdCancel_Click">
<script language="JavaScript> document.all["cmdCancel"].onclick = new function("Page_ValidationActive=false;");
</script>
The effect of these last two examples is that all client-side validation has been
turned off when the Cancel button is pressed. You will still have to bypass server-side
validation if the server code uses the Page.IsValid property.
There are a few drawbacks with these examples
that I'd like to mention. First, you will receive a JavaScript error on the client
when executing the code in the examples in any browser other than Microsoft® Internet
Explorer 4.0 or higher. The reason is that the Page_ValidationActive property only
exists when the user is using Internet Explorer 4.0 or higher. Also, the examples
turn off validation for the entire form, not just certain controls. I will show
you how to get around these drawbacks.
Disabling Server Validation
Another way to disable form validation is through
server-side programming. There are a variety of ways to accomplish this task through
the control's Enabled, Visible, and Display properties. Each has its pros and cons.
You should be careful to note which properties disable validation on the client
versus the server and be aware of the effect this might have on overall validation.
Disabling validation through server-side code
gives you the flexibility to turn off validation for certain controls and not the
entire page, and also allows this to be accomplished at run time. This is important
since you can respond to certain events before you decide to turn off the validation.
For example, based on a user's security level, you might want a field to be required
only at specific times.
Disabling Client Validation
As I mentioned, there are drawbacks to disabling
all client-side form validation with the methods already discussed. You can circumvent
these drawbacks by using code I'll describe in this section.
If you're like me and want to separate display
code from processing code (even to go as far as not embedding JScript in the .aspx
file), you can create your own custom control for turning off client-side and server-side
validation for certain validation controls. I will go through a simple example of
how to disable multiple validation controls from a server-side button control without
putting any JScript functions in the .aspx file.
I built a small application, MyApp, that has
one page (MyPage1). The page includes a field for editing the number of copies of
a book in inventory (I'll assume the user has chosen this on another page). There
is a button to cancel the editing (which acts as a reset button) and one to update
the number of copies. .gif) Figure 1 Valid Number
You can also add a new title to the inventory
along with the number of copies that are available. Figure 1
shows the page when it is first displayed. Figure 2
shows the page when a user has provided invalid input in the Edit section's Number
Available field and moved the focus to another control. Placing the cursor over
the error image displays the error and a solution. .gif) Figure 2 Invalid Entry
Included in the page are form validation controls
for each of the fields. All fields have a Required Field Validation control, while
the numeric fields have a Regular Expression Validation control to make sure the
input value is numeric. When the user clicks Save Changes, I want the form to be
passed back even though there may be errors in the Add section of the form. The
same is true when the user clicks Add to Inventory when there may be errors in the
Edit section of the form.
Building the Custom Control
Figure 3 shows all the code for this custom control,
which takes the place of a regular Submit button and turns off client-side validation.
Let's walk through the code step by step.
The first detail to notice is the definition
of the namespace. When creating a Web Control through the Visual Studio® .NET IDE,
this isn't automatically included. I included it in order to reference the control
on my Web page.
Next, I made sure the custom control extended
the functionality of a base control. In this instance, I used a button control as
the base for the custom control. I extended this functionality with the line: Inherits System.Web.UI.WebControls.Button
The next step was to set up a property to accept
a list of form validation controls that I wanted the custom control to disable.
I accomplished this by setting up a public property that I called NoFormValList
and declared the Get and Set procedures, which store their value in the State object
for persistence and easy retrieval.
One important thing to note about the Get procedure
is the use of the statement: If o Is Nothing Then
It took me a while to figure out what happened to our old friend Null. Since everything
is now an object, Null in Visual Basic® .NET is replaced with Nothing. The only
exception to this occurs when returning a value from the database; in this case
the value can be of type System.DBNull. So now, instead of using the IsNull function,
everything should be tested against Nothing. Also note that when testing against
objects, you need to use the Is operator.
Next, I needed to override the Render method
of the button control because I wanted to make it emit extra code if the browser
allowed client-side validation. Within this subroutine, the first thing I needed
to check, after making sure there were validation controls to disable, was which
browser was being used. The following line obtains a reference to the Request object
on the page: Dim theRequest As System.Web.HttpRequest = _ System.Web.HttpContext.Current.Request
Once I had this reference, I checked against it for the browser type and major version.
If the browser is Internet Explorer 4.0 or higher, I know that client-side validation
will occur. (For more information on the HttpContext object, check out
The ASP Column in the July 2001 issue of MSDN® Magazine.)
Within this conditional, I used the Output object
to send text to the HTML page. I began by setting up a JScript function that does
the actual disabling of the specified validation controls. I appended the control's
ID property to the name of the function so that the function was uniquely identified
on the page. If I didn't do this but left multiple instances of this control on
the page, all of the functions would be named exactly the same and only the last
one declared would be executed.
Then, using the Split function to put the list
into an array, I looped through the array generating the JScript code necessary
to disable the validation control. The client-side ValidatorEnable function handled
this for me. By specifying false, the function disabled the validation control.
One important thing to note about the loop itself
is the use of the new GetUpperBound method. This method is available in arrays and,
unlike the Visual Basic 6.0 UBound function, it actually returns the upper bound
of the array. For instance, if I had a zero-based, single-dimension array of 10
items, it would contain elements 0 through 9. The Visual Basic 6.0 UBound function
would return 10, but the new GetUpperBound method will return 9. Also note that
the GetUpperBound method requires the dimension for the upper bound. This is also
zero-based, so the first dimension is referenced as 0.
After I closed out the function, I added a couple
of attributes to the control's output. The first was the onServerClick attribute,
which tells the page which method to execute when it returns to the server. I needed
to set this, otherwise when I appended the normal onClick attribute the application
wouldn't know to execute anything on the server side. I constructed the attribute's
value based on the control's ID. This gave me the default name of the event on the
server.
The second attribute I appended was the onClick
attribute. This overrides the normal onClick event and points its value to the new
JScript function I just defined. When ASP.NET renders the page, it adds an onClick
attribute to any Submit buttons for client-side validation purposes. Since I handled
the validation manually, I included the code that ASP.NET would have inserted into
the extra onClick attribute in the onClick attribute I added. This extra code is
what calls the client-side validation routines and is specified as:
if typeof(Page_ClientValidate) == 'function') Page_ClientValidate();
Later I will show you how to disable the extra onClick attribute from appearing.
Now when the user clicks on the button, the
client-side onClick function executes. When it gets to the server, the normal server-side
ControlName_Click event fires.
The last two lines of the routine apply to all
browsersâ"not just Internet Explorer 4.0 or higher. The first line prevents ASP.NET
from inserting the client-side validation call into an extra onClick attribute.
The last line of the routine, MyBase.Render(output), writes out the code for the
control. Notice that it is outside of the conditional since I have to render the
control no matter what browser is being used.
Next I needed a way to turn off the server-side
validation of the same validation controls. The DisableServerSideValidation method
handles this for meâ"I just needed to call it in the right place.
The first thing this method does, after checking
to make sure there are validation controls to disable, is break up the list of validation
controls that you want to disable into an array. The code loops through the array
again, but this time for server-side processing. I used the FindControl function
to obtain a reference to the current control in the list.
After validating that the control exists (note
the use of the Is operator again), I used a Select Case conditional on its type
to determine what to do next. In each of the Case statements, I converted the control
into its real type and set its IsValid property to True. Since all of this occurs
after all of the validation controls have been validated, this has the effect of
overriding the invalidity of any of the validation controls in the list. Therefore,
when the Page.IsValid property is called, it will return True (as long as the other
validation controls not in the list are valid).
That's it for the custom control. Let's move
on to the page itself and see how to use this new control to turn off the validation.
Using the Custom Control in the Display
The display portion of the page is in the .aspx
file. At the top of the page, just under the Page declaration, I included a reference
to the new control's namespace so that I could use the control on the page. I did
this by making the following declaration:
<%@ Register TagPrefix="nfvc" Namespace="MyApp.NoFormValControls" Assembly="MyApp"
%>
Note the use of the application name in the namespace attribute. I have seen many
instances where the application name is not used, but I have not gotten the registration
to work without it. Also note that the Assembly attribute is required. I simply
set it to the name of the application.
Now I can put my control within the server-side
form. You can get the full code for the MyPage1.aspx file at the link at the top
of this article. Next, I'll look at adding the Save Changes button to the page.
Let's go ahead and assume that the Add section's
Title field has a required field validator with the ID of valReqTitle and that the
Add section's Number Available field has a regular expression validator and a required
field validator with the IDs of valREAdd and valReqAdd, respectively. I then put
the Save Changes button on the form with the following code:
<nfvc:NoFormValButton id="Save" runat=Server text="Save Changes >>"
NoFormValList="valReqTitle,valREAdd,valReqAdd"> </nfvc:NoFormValButton>
Using the TagPrefix of nfvc that I defined at the top of the page, I declared the
NoFormValButton control, setting the runat, id, and text attributes. I also set
the new NoFormValList attribute to a comma-separated list of validation controls
I want to turn off when the Save Changes button is clicked. Figure 4 shows the source code when viewed through the
browser for Internet Explorer 4.0 or higher. For all other browsers (that don't
support the client-side validation), the control looks like the following:
<input type="submit" name="Save" value="Save Changes >>" id="Save"
/>
I then added the Add to Inventory and Cancel
Editing buttons, indicating which validation controls to disable in their respective
NoFormValList attributes.
Using the Custom Control on the Server
The last thing to look at is the .vb codebehind
page, which handles all of the processing on the server side. One of the first things
to do on this page is include a reference to my new control. I did this with a normal
Imports statement at the top of the page:
Imports MyApp.NoFormValControls
Within the class definition of the page itself, I hooked the page controls into
local controls, making sure I declared the buttons with a type of NoFormValButton.
Be sure to note the requirement of the Handles
ControlName.Event directive at the end of each of the event declarations.
If you omit this directive, your procedures won't fire. For example, the Click event
of the Add button should be declared:
Protected Sub Add_Click(ByVal Sender as object, _ ByVal e as Eventargs) Handles
Add.Click
Lastly, in each of the Click events for the
buttons is a call to the DisableServerSideValidation method for the button. This
disables the server-side validation of the list of controls I defined back on the
.aspx page. The call for the Save Changes button is simply:
Save.DisableServerSideValidation()
After I hooked in the other Click events, I
was finished. When I tied this all together, I got a page that allows you to have
invalid input in the Add to Inventory part, but still lets you cancel editing and
save changes. Also, it allows you to have invalid input in the Edit Inventory part,
while leaving Cancel Editing and Add to Inventory working. As an added benefit (or
perhaps the best benefit), you now have a custom server control that you can reuse
in many other applications.
Conclusion
Form validation controls are just one of the
many new tools available to developers for performing the kinds of tasks that are
frequently required of Web sites. If these tools aren't exactly what you need for
all your scenarios, you can take advantage of the features of ASP.NET and Visual
Basic .NET to override and extend these controls to make them fit your particular
needs. |