Thursday, April 10, 2008

Custom validator controls : Change style of label when error occurs

ASP.net

We had this unique requirement from a client that when a validation failure occurs like "required field is not filled", the corresponding label must be highlighted with a different color. As all of you might already be aware, we attach the validator controls to the control that needs to be validated and not the label. For eg, if you have a "Customer name" field with a textbox (txtCustomer) which is mandatory, you add a requiredFieldValidator with its ControlToValidate property = txtCustomer.

So how do you now highlight the label "Customer name" .. lets say with a different background color. Ofcourse, doing that on the server is easy, but that negates the reason of using validator controls which does everything on the client (browser). So I decided to build a custom control by inheriting from the standard requriedFieldValidator control. I added a new property called LabelToHighlight which will accept a control name whose styles needs to be changed when an error occurs. I reaserched on how to allow user (consumer the control) to be able to select a label (like you selecting controls when setting the ControlToValidate property) and not just type in a control name and I came across typeconvertor settings available for properties .. anyway, given below is some of the code .. you can write to me for more explanation if needed ..


'Created by Rejo on Aug 23rd 2007
' Standard field validators has just the controltovalidate property which can be set to specify which
' controls needs to be validated. But the delivery.com project requires the errors to highlight the label
' of the control which is been validated.
' This custom validator does just that.
' A new property added gives option to the developer to select a control which gets highlighted with a different style.
' The styles are set as embeded resource and should be changed as per the requirement of the project
' The styles too could have been exposed as public properties, but that would be each control will have to manually
' set by the developer.
' The javascript which changes the style is also embeded into the project
' ONLY THE DLL NEEDS TO BE REFERENCED IN THE MAIN PROJECT which will consume these controls

Imports Microsoft.VisualBasic
Imports System.Web.UI
Imports System.ComponentModel
Imports System.Web.UI.WebControls

Namespace Controls

_
Public Class CustomRequiredValidator
Inherits System.Web.UI.WebControls.RequiredFieldValidator
Dim lstrLabelToHighlight As String

_
Public Property LabelToHighlight() As String
'property to hold the name of the label control which would be highlighted when the error occurs
Get
Return lstrLabelToHighlight
End Get
Set(ByVal value As String)
lstrLabelToHighlight = value
End Set
End Property

Protected Overrides Sub AddAttributesToRender(ByVal writer As System.Web.UI.HtmlTextWriter)
'set the display property to none
Me.Display = ValidatorDisplay.None
MyBase.AddAttributesToRender(writer)
'add the custom properties
writer.AddAttribute("LabelToHighlight", Me.LabelToHighlight)
End Sub

Private Sub CustomRequiredValidator_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
Dim ctlParent As System.Web.UI.Control = Me.Parent
Dim lLableHighlight As Label = TryCast(ctlParent.FindControl(LabelToHighlight), Label)

While lLableHighlight Is Nothing
ctlParent = ctlParent.Parent
If ctlParent IsNot Nothing Then
lLableHighlight = TryCast(ctlParent.FindControl(LabelToHighlight), Label)
Else
Throw New Exception("Control to highlight is not found.")
End If
End While

LabelToHighlight = lLableHighlight.ClientID

'check if the script is already present and if not, then add it
If Not Me.Page.ClientScript.IsClientScriptIncludeRegistered("ControlsCommon.js") Then
Dim lstrScriptLocation As String = Page.ClientScript.GetWebResourceUrl(Me.GetType(), "Delivery.ControlsCommon.js")
Page.ClientScript.RegisterClientScriptInclude("ControlsCommon.js", lstrScriptLocation)

' add the style .. assumming that the style too would be added only once along with the js file

Dim lstrLocation As String = Page.ClientScript.GetWebResourceUrl(Me.GetType(), "Delivery.ControlStyle.css")
Dim lobjIncludeLiteral As LiteralControl = New LiteralControl(String.Format(lstrTemplate, lstrLocation))
CType(Page.Header, HtmlControls.HtmlHead).Controls.Add(lobjIncludeLiteral)

'register submit script which will call the script which will highlight the control if there is a error
Me.Page.ClientScript.RegisterOnSubmitStatement(Me.GetType(), "HighlightLabelSubmit", "UpdateErrorLabel();")
End If
End Sub
End Class
End Namespace



Code from the COMMON.js file



Function UpdateErrorLabel()
{
var lobjValidator;
//first reset all the existing validators to default style
for (i = 0; i < Page_Validators.length; i++)
{
lobjValidator = document.getElementById(document.getElementById(Page_Validators[i].id).getAttribute('LabelToHighlight'));
if (lobjValidator != null)
{
lobjValidator.className = 'lblnormal';
}
}


//change the style for all error labels
for (i = 0; i < Page_Validators.length; i++)
{
if (!Page_Validators[i].isvalid)
{
//lobjValidator = document.getElementById(Page_Validators[i].LabelToHighlight);
lobjValidator = document.getElementById(document.getElementById(Page_Validators[i].id).getAttribute('LabelToHighlight'));
if (lobjValidator != null)
{
//lobjValidator.setAttribute('class', 'lblerror');
//lobjValidator.setAttribute('className', 'lblerror');
lobjValidator.className = 'lblerror';
}
}
}
}



This does have some flaws which I have learnt to overcome like sometimes when you add the this control, the highlight does not work. As you can see from the code, I have to add on to the standard validation code that asp.net generates which checks for the isvalid property and then change the style when it is false. Some my functions get added to the front and so this js always finds the isvalid = true and does not validate. For these cases, I just remove the Custimvalidator and add it again and it works .. :-) ..

Note, you will need the style 'lblError' etc to be available in your stylesheet referred by the page ..

This line is not getting accepted by this blogpost when added in my code above..

it must be in the prerender event .. i will try and make some changes to the code so that this post gets accepted
Dim lstrTemplate As String = "<link rel='stylesheet' text='text/css' href='{0}' CLOSING TAGS"

No comments:

Post a Comment