Categories

Blogroll

Search

A Quick Fix for the Validator SetFocusOnError Bug

March 25th, 2008 by kerrysoft and tagged , , ,



The ASP.NET validators have this nice property called “SetFocusOnError” that is supposed to set the focus to the first control that failed validation. This all works great until your validator control is inside a naming container. I ran into this recently when using validators in a DetailsView. Take this simple example:

Also see: Finalization

<%@ Page Language=”C#” %>
<script runat=”server”>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
DataBind();
}
</script>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title></title>
</head>
<body>
<form id=”_frm” runat=”server”>
<asp:DetailsView
ID=”dv1″
DefaultMode=”Edit”
DataSource=’<%# new object[1] %>’
runat=”server”
>
<Fields>
<asp:TemplateField HeaderText=”First Name:”>
<EditItemTemplate>
<asp:TextBox ID=”FirstNameTextBox” runat=”server” />
<asp:RequiredFieldValidator
ID=”FirstNameValidator1″
ControlToValidate=”FirstNameTextBox”
ErrorMessage=”First name is required.”
Display=”Dynamic”
EnableClientScript=”false”
SetFocusOnError=”true”
ValidationGroup=”bug”
Text=”*”
runat=”server”
/>
</EditItemTemplate>
</asp:TemplateField>
</Fields>
<FooterTemplate>
<asp:ValidationSummary
ID=”vs1″
DisplayMode=”List”
ValidationGroup=”bug”
runat=”server”
/>
<asp:Button
ID=”Button1″
Text=”Post Back”
ValidationGroup=”bug”
runat=”server”
/>
</FooterTemplate>
</asp:DetailsView>
</form>
</body>
</html>

.csharpcode,.csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode.rem { color: #008000; }
.csharpcode.kwrd { color: #0000ff; }
.csharpcode.str { color: #006080; }
.csharpcode.op { color: #0000c0; }
.csharpcode.preproc { color: #cc6633; }
.csharpcode.asp { background-color: #ffff00; }
.csharpcode.html { color: #800000; }
.csharpcode.attr { color: #ff0000; }
.csharpcode.alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode.lnum { color: #606060; }

If you run this page and do a view source you’ll see that the FirstNameTextBox gets rendered like this:
<input name=”dv1$FirstNameTextBox” type=”text” id=”dv1_FirstNameTextBox” />

If you just do a post back without entering a value to cause the validator to fail it will output this line of java script in an attempt to set the focus to the invalid element:

Also see: Applied Metamodelling: A Foundation for Language Driven Development

Also see: Blogging and Newspapers, a Lesson in How Not to Brand and Market

WebForm_AutoFocus(’FirstNameTextBox’);

.csharpcode,.csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode.rem { color: #008000; }
.csharpcode.kwrd { color: #0000ff; }
.csharpcode.str { color: #006080; }
.csharpcode.op { color: #0000c0; }
.csharpcode.preproc { color: #cc6633; }
.csharpcode.asp { background-color: #ffff00; }
.csharpcode.html { color: #800000; }
.csharpcode.attr { color: #ff0000; }
.csharpcode.alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode.lnum { color: #606060; }

See anything wrong with this? It would seem that the validators just use the string value you typed in for the ControlToValidate property rather than doing a FindControl and using the UniqueID. This is exactly what happens and I verified it with reflector. The Validate method on BaseValidator does this:
if ((!this.IsValid && (this.Page != null)) && this.SetFocusOnError)
{
this.Page.SetValidatorInvalidControlFocus(this.ControlToValidate);
}

.csharpcode,.csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode.rem { color: #008000; }
.csharpcode.kwrd { color: #0000ff; }
.csharpcode.str { color: #006080; }
.csharpcode.op { color: #0000c0; }
.csharpcode.preproc { color: #cc6633; }
.csharpcode.asp { background-color: #ffff00; }
.csharpcode.html { color: #800000; }
.csharpcode.attr { color: #ff0000; }
.csharpcode.alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode.lnum { color: #606060; }

If you follow the call to SetValidatorInvalidControlFocus you’ll see that it never resolves the full UniqueID of the control that its going to set focus to.

 

Ok, so this sucks. How do I work around it. My solution was to simply ditch using the SetFocusOnError property and implement the focus logic myself which is actually pretty easy. I overrode Validate method on my Page like this:
Customer Help Solution: jbTop is Jabber/XMPP Live Chat Soulution for your website.

Also see: Spring Web Flow features and feedback request

Also see: Load(AssemblyName)

Also see: Applied Metamodelling: A Foundation for Language Driven Development

Also see: Applied Metamodelling: A Foundation for Language Driven Development

Also see: Load(AssemblyName)

Also see: SIGPLAN Workshop on Undergraduate Programming Language Curriculum

Also see: Microformats are like RFID tags for the Web

Also see: Channel 9 Interview

Also see: Microformats are like RFID tags for the Web

Also see: Win friends and influence your team

Also see: SIGPLAN Workshop on Undergraduate Programming Language Curriculum

Also see: Generics and .NET

Also see: Load(AssemblyName)

Also see: Java Concurrency, another series on its issues

Also see: Spring Web Flow features and feedback request

Also see: A Quick Fix for the Validator SetFocusOnError Bug

Also see: LINQ – The Uber FindControl

Also see: Sometimes, it’s the small things..

public override void Validate(string group)
{
base.Validate(group);

// find the first validator that failed
foreach (IValidator validator in GetValidators(group))
{
if (validator is BaseValidator && !validator.IsValid)
{
BaseValidator bv = (BaseValidator)validator;

// look up the control that failed validation
Control target =
bv.NamingContainer.FindControl(bv.ControlToValidate);

// set the focus to it
if (target != null)
target.Focus();

break;
}
}
}

If your using C# 3 this is even easier using LINQ:
public override void Validate(string group)
{
base.Validate(group);

// get the first validator that failed
var validator = GetValidators(group)
.OfType<BaseValidator>()
.FirstOrDefault(v => !v.IsValid);

// set the focus to the control
// that the validator targets
if (validator != null)
{
Control target = validator
.NamingContainer
.FindControl(validator.ControlToValidate);

if (target != null)
target.Focus();
}
}


.csharpcode,.csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode.rem { color: #008000; }
.csharpcode.kwrd { color: #0000ff; }
.csharpcode.str { color: #006080; }
.csharpcode.op { color: #0000c0; }
.csharpcode.preproc { color: #cc6633; }
.csharpcode.asp { background-color: #ffff00; }
.csharpcode.html { color: #800000; }
.csharpcode.attr { color: #ff0000; }
.csharpcode.alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode.lnum { color: #606060; }

Live Help Server: Jerry Messenger Server is Live Chat with Users on your websites.

I hope this saves someone the headache of tracking this down.
.csharpcode,.csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode.rem { color: #008000; }
.csharpcode.kwrd { color: #0000ff; }
.csharpcode.str { color: #006080; }
.csharpcode.op { color: #0000c0; }
.csharpcode.preproc { color: #cc6633; }
.csharpcode.asp { background-color: #ffff00; }
.csharpcode.html { color: #800000; }
.csharpcode.attr { color: #ff0000; }
.csharpcode.alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode.lnum { color: #606060; }

http://weblogs.asp.net/dfindley/archive/2007/06/29/a-quick-fix-for-the-validator-setfocusonerror-bug.aspx

Posted in Technology | Comments Off

Create a free edublog to get your own comment avatar (and more!)

Comments are closed.