In this two part series of jQuery Form Validation in ASP net I’ll show you how to override the built-in ASP.net validation functions with your own jQuery-ized versions.
Turn your boring ASP.net form validation controls into intuitive, user-friendly, and just all around snazzy feature of your ASP.net web forms.
You’ll make your users want to throw validation errors!
In Part 1 I showed how to override the built-in javascript and highlight an input control if it is not valid.
Here’s the WebForm we finished in Part 1:
<form runat="server" id="Form1"> <asp:Label ID="lblEmail" runat="server" associatedcontrol="txtEmail" Text="Email" /> <asp:TextBox ID="txtEmail" runat="server" Width="300px" /> <asp:RequiredFieldValidator ID="reqEmail" runat="server" Text="*" ErrorMessage="Email is required." ControlToValidate="txtEmail" Display="Dynamic" /> <asp:RegularExpressionValidator ID="rxpEmailCheck" runat="server" ControlToValidate="txtEmail" Text="*" ErrorMessage="Email is not valid" Display="Dynamic" ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" /> <br /> <asp:Button ID="btnSubmit" runat="server" Text="Submit" /> <br /> <!-- In Part 2 we'll get fancy with the validation summary --> <asp:ValidationSummary ID="valSummary" runat="server" HeaderText="Please correct the following:" /> </form> <!-- Normally I would put the following in a Master Page and include a ContentPlaceHolder id="Scripts" after it. This file has to be referenced after the ASP.net calls the web resources (inside the opening <form> tag) --> <script type="text/javascript" src="js/validators.js"></script>
Here’s the <head> where the jQuery reference is added along with a couple basic styles:
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Fancy Up ASP.net Validation Controls with jQuery Part 01</title> <script type="text/javascript" src="http://res.codingboynamedtracy.com/js/jquery.js"></script> <style type="text/css"> body { font-family: Helvetica, Arial, sans-serif; } .validationError { background-color: #d7d7d7; color: #5b5b5b; border: 1px solid #f04138; } </style>
When the button (btnSubmit) is clicked the form is validated on the client side and if there are any validation errors, the form field will be highlighted with a red border. Fairly straightforward.
For part 2 I want to use the Validation Summary asp.net to show the errors as it normally does but also add some functionality to make it more user friendly. This requires us to override the ValidationOnSubmit function built into ASP.net. Here’s the original function.
function ValidationSummaryOnSubmit(validationGroup) { if (typeof(Page_ValidationSummaries) == "undefined") return; var summary, sums, s; var headerSep, first, pre, post, end; for (sums = 0; sums < Page_ValidationSummaries.length; sums++) { summary = Page_ValidationSummaries[sums]; summary.style.display = "none"; if (!Page_IsValid && IsValidationGroupMatch(summary, validationGroup)) { var i; if (summary.showsummary != "False") { summary.style.display = ""; if (typeof(summary.displaymode) != "string") { summary.displaymode = "BulletList"; } switch (summary.displaymode) { case "List": headerSep = "<br>"; first = ""; pre = ""; post = "<br>"; end = ""; break; case "BulletList": default: headerSep = ""; first = "<ul>"; pre = "<li>"; post = "</li>"; end = "</ul>"; break; case "SingleParagraph": headerSep = " "; first = ""; pre = ""; post = " "; end = "<br>"; break; } s = ""; if (typeof(summary.headertext) == "string") { s += summary.headertext + headerSep; } s += first; for (i=0; i<Page_Validators.length; i++) { if (!Page_Validators[i].isvalid && typeof(Page_Validators[i].errormessage) == "string") { s += pre + Page_Validators[i].errormessage + post; } } s += end; summary.innerHTML = s; window.scrollTo(0,0); } if (summary.showmessagebox == "True") { s = ""; if (typeof(summary.headertext) == "string") { s += summary.headertext + "\r\n"; } var lastValIndex = Page_Validators.length - 1; for (i=0; i<=lastValIndex; i++) { if (!Page_Validators[i].isvalid && typeof(Page_Validators[i].errormessage) == "string") { switch (summary.displaymode) { case "List": s += Page_Validators[i].errormessage; if (i < lastValIndex) { s += "\r\n"; } break; case "BulletList": default: s += "- " + Page_Validators[i].errormessage; if (i < lastValIndex) { s += "\r\n"; } break; case "SingleParagraph": s += Page_Validators[i].errormessage + " "; break; } } } alert(s); } } } }
The role of the ValidationSummary is to simply gather all the validation errors on the form and either show them on the page (the default method) or show the errors in a JavaScript alert message box or both. I find no use for the alert box so I never use it.
Click on the btnSubmit the error message to see the outcome.
Link to an Invalid Control
By default the ValidationSummary shows a unordered list of messages as text. If you’re dealing with a small form with a couple fields then that’s probably ok. If you have a long form that requires a lot of scrolling this is problematic. In the case of our web form, if there were several additional fields then the error summary would show at the bottom of the page and would require the user to scroll and find which field is not valid. This is not ideal. How about if we update the display of the errors to provide a link directly to the field. This may help a little. In order to do that we need to add the original ValidationSummaryOnSubmit function to our custom validators.js file. Now let’s add the functionality to change the display from text to a hyperlink. Here’s the new function:
function ValidationSummaryOnSubmit(validationGroup) { if (typeof (Page_ValidationSummaries) == "undefined") return; var summary, sums, s; var headerSep, first, pre, post, end; for (sums = 0; sums < Page_ValidationSummaries.length; sums++) { summary = Page_ValidationSummaries[sums]; summary.style.display = "none"; if (!Page_IsValid && IsValidationGroupMatch(summary, validationGroup)) { var i; if (summary.showsummary != "False") { summary.style.display = ""; if (typeof (summary.displaymode) != "string") { summary.displaymode = "BulletList"; } switch (summary.displaymode) { case "List": headerSep = "<br>"; first = ""; pre = ""; post = "<br>"; end = ""; break; case "BulletList": default: headerSep = ""; first = "<ul>"; pre = "<li>"; post = "</li>"; end = "</ul>"; break; case "SingleParagraph": headerSep = " "; first = ""; pre = ""; post = " "; end = "<br>"; break; } s = ""; if (typeof (summary.headertext) == "string") { s += summary.headertext + headerSep; } s += first; for (i = 0; i < Page_Validators.length; i++) { if (!Page_Validators[i].isvalid && typeof (Page_Validators[i].errormessage) == "string") { // Add an <a> tag that will set the focus to the control and also scroll to // it on the page. s += pre + '<a href="javascript:;" onclick="window.scrollTo(0,$(\'#' + Page_Validators[i].controltovalidate + '\').focus().offset().top);">' + Page_Validators[i].errormessage + '</a>' + post; } } s += end; summary.innerHTML = s; window.scrollTo(0, 0); } if (summary.showmessagebox == "True") { s = ""; if (typeof (summary.headertext) == "string") { s += summary.headertext + "\r\n"; } var lastValIndex = Page_Validators.length - 1; for (i = 0; i <= lastValIndex; i++) { if (!Page_Validators[i].isvalid && typeof (Page_Validators[i].errormessage) == "string") { switch (summary.displaymode) { case "List": s += Page_Validators[i].errormessage; if (i < lastValIndex) { s += "\r\n"; } break; case "BulletList": default: s += "- " + Page_Validators[i].errormessage; if (i < lastValIndex) { s += "\r\n"; } break; case "SingleParagraph": s += Page_Validators[i].errormessage + " "; break; } } } alert(s); } } } }
Now if we run the page in the browser and click the submit button without providing an email you will notice a link to the field.
Making the ValidationSummary Sticky
That’s a good start. It’s pretty ugly though and one thing you’ll notice is that the ValidationSummary automatically scrolls to the top of the page. That is really annoying, especially if you put the ValidationSummary at the bottom of the page. I want the page to scroll to wherever the summary is on the page, so let’s change this line:
window.scrollTo(0,0);
To this:
window.scrollTo(0, $(summary).position().top);
You probably won’t notice much since our form is so small. If you wanted to test it you could add a bunch of paragraphs above the form so the page scrolls.
And this is nice and all but I want more. Why should you even have to scroll the page to see the validation errors? Why not make them static so that when you scroll you always see them? Now we’re talking!
Let’s add some CSS to make the ValidationSummary sticky. I created a CSS file and called it formvalidation.css. I moved the styles that were in the <head> to the new stylesheet and added a reference to it in the <head>.
First thing we need to do is add a CssClass to the ValidationSummary control. I’ve also added put an H2 around the HeaderText, so the ValidationSummary now looks like this
<asp:ValidationSummary ID="valSummary" CssClass="validationresults" runat="server" HeaderText="<h2>Please correct the following:</h2>" />
Now let’s add some classes to the stylesheet to make it “sticky”. The CSS looks like
.validationresults { bottom: 0; left: 0; width: 100% !important; padding: 20px !important; background: #ce281f !important; display: block; position: fixed; border-top: none !important; border-left: none !important; border-right: none !important; border-bottom: none !important; margin: 0px !important; color: #fff !important; z-index: 1000000; } .validationresults ul { list-style-type: square; list-style-position: inside; font-weight: bold; clear: both; width: 100%; } .validationresults h2 { margin: 0px 0 10px 0; color: #fff; font-weight: bold; } .validationresults li { float: left; display: block; width: 300px; padding: 0 0 0 20px; margin-left: 10px; font-weight: bold; } .validationresults li a { font-size: auto; font-weight: bold; color: #fff; }
Now run it in the browser and see what we’ve got.
Again, you won’t notice on this page, but if you have a page that scrolls the summary at the bottom will stay fixed so you can always see what the errors are no matter where on the page you are.
Collapse/Expand the ValidationSummary
This is great, but how about adding more features. How about if the browser window is small or screen resolution is low and the red box covers everything on the page? How about adding a show/hide button to the header (remember I put H2 tags around the HeaderText)? That will take some additional lines in the JavaScript function. Add the following below the last line we changes (window.scrollTo…):
var a = $('<a href="javascript:;" class="valClose">hide x</a>'); a.click(function () { $(this).toggleClass('collapsed'); if ($(this).html() == 'hide x') { $(this).html('show'); }else{ $(this).html('hide x'); }$(this).parent().children('ul').slideToggle(200); }); a.insertBefore($(summary).children('h2')); $(summary).append('<div class="clear"></div>');
Now add these styles to the CSS:
.clear { clear: both; } .valClose { display: block; float: right; width: 66px; height: 22.5px; margin-right: 20px; padding: 2px; text-align: center; } a.valClose { color: #fff; font-weight: bold; }
Now when we view it in the browser and click the submit button with no email entered we get a toggle link in the top right of the summary. Click on the hide x link and the summary collapses. Click show and it will expand again.
We’re getting somewhere now! Let’s take it further, shall we.
Adding Animation to the ValidationSummary
When the form is invalid the ValidationSummary currently just appears. The style setting in the JavaScript function goes from “none” to “” (blank, which essentially means it’s shown). Since we’re already using jQuery we can add a little animation to spice it up a little. Let’s go back to the ValidationSummaryOnSubmit function and make a couple more changes.
First we need to remove the line summary.style.display = “”; then add the following line after the line we added previously (when we added the show/hide link).
$(summary).animate({ height: 'show' });
The above line will slide the summary up from the bottom. You may wonder I didn’t use the jQuery function slideUp. The reason is that slideUp actually hides the element. slideDown shows it, but I don’t want the summary to slide down. That’s why I use the animate() {} method.
One final change is to change summary.style.display = “none”; to $(summary).hide();.
Now when you view this in the browser and click the btnSubmit you’ll see the red panel slide up from the bottom of the page. Of course you could use any jQuery animations. More on jQuery animate() can be found here. You could also reference jQuery UI in the <head> and use some of its animations.
$(summary).show('bounce', { times: 3 }, 300);
Add Images
One final step is to add a background image to the panel and image for the show/hide link and bullet images for the validation errors.
Here’s the updated CSS classes:
.validator { background: transparent url(images/validation/b-validation-error.png) no-repeat; display: block; position: absolute; width: 16px; height: 16px; color: #ffffff; text-indent: -10000px; border: none; /*padding: 4px;*/ font-weight: bold; font-size: 10px; z-index: 1000; } .validationresults { bottom: 0; left: 0; width: 100% !important; padding: 20px !important; background: #ce281f url(images/validation/b-bottom-panel.gif) repeat-x !important; display: block; position: fixed; border-top: none !important; border-left: none !important; border-right: none !important; border-bottom: none !important; margin: 0px !important; color: #fff !important; z-index: 1000000; } .validationresults li { float: left; display: block; background: url(images/validation/b-bullet.gif) no-repeat; width: 300px; padding: 0 0 0 20px; margin-left: 10px; font-weight: bold; } .valClose { display: block; float: right; width: 66px; height: 22.5px; margin-right: 20px; padding: 2px; text-align: center; text-indent: -20000px; background: #ce281f url(images/validation/hide-show-icon.gif) no-repeat 0 0; }
How about Validation Groups?
A commenter on Part 1 asked about using this with ValidationGroups. My answer for this is very technical: It works with validation groups.