Introduction
In application development, there is always the need for validating input controls. To validate input controls, ASP.NET has a set of validation controls. To apply validation on input controls, you require to attach a validation control with the input control.
Here, I will discuss about an extended control which doesn't require attaching a validation control, but just needs specifying the input type.
Implementation
Custom control implementation
As this is a generic control which can be used by any developer in any ASP.NET application, it inherit the ASP.NET TextBox
control to support a basic textbox control and to add extra features for validation; it's basically a custom control, i.e., a custom textbox control.
Properties of the control
All properties use the viewstate to persist values. Another thing to note here is the property appends the ID of the control so that if two textbox controls are dropped on the same page, they do not conflict with each other's property values.
ValidationType
This property allows applying a validation type on the textbox control.
The following validation types are supported by the textbox control:
None
– allows to enter any type of data.Integer
– allows to enter only integer. E.g., 123.Numeric
– allows to enter only integer and decimal point values. E.g., 123.12 or 123.Alpha
– allows to enter alphabets. E.g., A-Z or a- z.AlphaNumeric
– allows to enter alpha and numeric data. E.g., A-Z or a-z or 0-9.Custom
– allows to enter data based on patterns specified by the user.Required
– allows to enter any kind of data but you are required to enter data in the field.RequiredAndInteger
– allows to enter integer and must enter data.RequiredAndNumeric
– allows to enter numeric and must enter data.RequiredAndAlpha
– allows entering alphabets and must enter data.RequiredAndAlphaNumeric
– allows to enter alphanumerics and must enter data.RequiredCustom
– allow to enter data based on pattern and must enter data.
AssociatedLabelText
This property allows to set the label that should be displayed with an error message when invalidate data is entered.
public string AssociatedLableText
{
get
{
if (ViewState["LableText" + this.ID.ToString()] == null)
return "Textbox";
return (string)(ViewState["LableText" + this.ID.ToString()].ToString());
}
set
{
ViewState["LableText" + this.ID.ToString()] = value;
}
}
CustomPattern
This property allows to set a custom Regular Expression to validate the entered data. This property is used when the user wants to validate complex data like email.
public string CustomPattern
{
get
{
if (ViewState["CustomPattern" + this.ID.ToString()] == null)
return string.Empty;
return (string)(ViewState["CustomPattern" + this.ID.ToString()].ToString());
}
set
{
ViewState["CustomPattern" + this.ID.ToString()] = value;
}
}
ReadOnly
This property causes the textbox control to be displayed as a label control so that its does not allow editing data.
public string ReadOnly
{
get
{
if (ViewState["ReadOnly" + this.ID.ToString()] == null)
return string.Empty;
return (string)(ViewState["ReadOnly" + this.ID.ToString()].ToString());
}
set
{
ViewState["ReadOnly" + this.ID.ToString()] = value;
}
}
LabelCSSClass
This property allows to set the CSS class when the textbox has the ReadOnly
property set to true
.
public string LabelCSSClass
{
get
{
if (ViewState["LabelCSSClass" + this.ID.ToString()] == null)
return string.Empty;
return (string)(ViewState["LabelCSSClass" + this.ID.ToString()].ToString());
}
set
{
ViewState["LabelCSSClass" + this.ID.ToString()] = value;
}
}
ShowWaterMark
This property allows to set the watermark in textbox when property set to true.
public bool ShowWaterMark
{
get
{
if (ViewState["ShowWaterMark" + this.ID.ToString()] == null)
return false;
return Convert.ToBoolean(ViewState["ShowWaterMark" +
this.ID.ToString()].ToString());
}
set
{
ViewState["ShowWaterMark" + this.ID.ToString()] = value;
}
}
WaterMarkText
This property allows to set watermark in textbox when ShowWaterMark propety is set to true.
public string WaterMarkText
{
get
{
if (ViewState["WaterMarkText" + this.ID.ToString()] == null)
return string.Empty;
return (string)(ViewState["WaterMarkText" +
this.ID.ToString()].ToString());
}
set
{
ViewState["WaterMarkText" + this.ID.ToString()] = value;
}
}
GroupId
This property is used by the validation function to know with which group it is associated. E.g., if groupId
= ‘A’ for the textbox, then the validation event is fired by the button control having groupId
= ‘A’ and the textbox control is validated. In this case, it is not going to be validated by the control having groupId = ‘B’.
Note: this property is used by the JavaScript only and it's added to the control directly; it works the same as the group property in .NET, but the difference is this is used by the JavaScript function.
Overridden methods
The Render
method of the control cause rendering of the control on the client with the HtmlTextWriter
object. By using this method, changing the rendering of the textbox control is possible.
Render
protected override void Render(HtmlTextWriter writer)
{
If the ReadOnly
property of the control is true
, than only span
is going to be rendered in place of the textbox control so it is not displayed as an editable control.
if (this.ReadOnly)
{
writer.Write(@"<span class=""{0}"">{1}</span>",
this.LabelCSSClass, this.Text);
}
If the ReadOnly
property of the control is false
, than it calls the ApplyValidation
method which adds JavaScript and validates the data entered by the client in the textbox control.
else if (!this.ReadOnly)
{
string strError= ApplyValidation(writer);
base.Render(writer);
if (((int)this.DataType) > 4)
{
writer.Write(strError);
}
}
ApplyValidation
private string ApplyValidation(HtmlTextWriter writer)
{
The following line of code defines errorMsg
and the script which is going to be bound with the textbox control.
string errorMsg = string.Empty;
string script = string.Empty;
As you see below, if DataType
has a value more than 5, it adds the required attribute with the value true
, which is used by JavaScript to check whether the value is present or not. It also binds the keyup
JavaScript method with the onBlur
and onKeyUp
events. A span
tag is also rendered to display an error message when there is no data present in the textbox control.
if (((int)this.DataType) > 5)
{
this.Attributes.Add("isRequired", "true");
this.Attributes.Add("onKeyUp", "keyup('" + this.ClientID + "')");
this.Attributes.Add("onBlur", "keyup('" + this.ClientID + "')");
errorMsg = string.Format(@"<span id='spError{2}' style='display:" +
@"none;' >{0} {1}</span>",
"Enter value in ", this.AssociatedLableText,
this.ClientID);
}
The below line of code adds the ShowWaterMark
attribute to the textbox rendered at the client, which is used by the JavaScript function.
this.Attributes.Add("ShowWaterMark", this.ShowWaterMark.ToString());
If the ShowWaterMark
value is set to true, than it adds the LabelValue
attribute to the textbox control which is displayed as the watermark in the textbox:
if(this.ShowWaterMark)
this.Attributes.Add("LabelValue", this.WaterMarkText);
If DataType
is less than 6, it means it is not required to attach the showWaterMarkText
method to the onblur
event.
if (((int)this.DataType) < 6)
this.Attributes.Add("onBlur", "showWaterMarkText('" + this.ClientID + "')");
If the DataType
is Integer
, requiredAndInteger
, numeric
, or requireAndNumeric
, it binds the IntegerAndDecimal
method with onKeyPress
so that it is only allowed to enter integer or decimal data in the textbox control.
if (this.DataType == ValidationType.integer||
this.DataType == ValidationType.requiredAndInteger)
{
script="IntegerAndDecimal(event,this,'false')";
}
if (this.DataType == ValidationType.numeric ||
this.DataType == ValidationType.requiredAndNumeric)
{
script = "IntegerAndDecimal(event,this,'true')";
}
An important thing to note here is the third argument passed to the JavaScript function: when the value passed to the argument is true
, it means it allows to enter decimal data, and if it is false
, it allows to enter integer data without a decimal point.
If the DataType
is alpha
, requiredAndalpha
, alphaNumeric
, or requireAndAlphaNumeric
, it binds the AlphaNumericOnly
method with onKeyPress
so that it allows to enter integer or decimal data only in the textbox control.
if (this.DataType == ValidationType.alpha ||
this.DataType == ValidationType.requiredAndAlpha)
{
script = "return AlphaNumericOnly(event,'true')";
}
if (this.DataType == ValidationType.alphaNuemric ||
this.DataType == ValidationType.requiredAndAlphaNumeric)
{
script = "return AlphaNumericOnly(event,'false')";
}
An important thing to note here is the second argument passed to the JavaScript function: when the value passed to the argument is true
, it allows to enter alpha characters only, and when it is false
, it allows to enter alphanumeric characters.
If the DataType
is custom
or requiredCustom
, it binds the checkReg
function with the onBlue
event. It also adds a span tag with the text box to display an error message when the data entered doesn't match with the Regular Expression assigned to the CustomPattern
property. It adds the pattern
attribute with the textbox to validate the data.
if (this.DataType == ValidationType.custom ||
this.DataType == ValidationType.requiredCustom)
{
errorMsg = errorMsg +
string.Format(@"<span id='spCuError{2}' style='display:none;' >{0} {1}</span>",
"Invalid data in ", this.AssociatedLableText, this.ClientID);
this.Attributes.Add("pattern", this.CustomPattern);
if (this.DataType == ValidationType.custom)
this.Attributes.Add("onBlur", "checkReg(this,'" + this.CustomPattern + "');");
else
this.Attributes.Add("onBlur", "keyup('" + this.ClientID +
"'); checkReg(this,'" + this.CustomPattern + "');");
}
If the TextMode
of the textbox control is set to MultiLine
, it binds the CountText
method with the onKeyPress
event, so that it doesn't allow to enter characters more than a maximum length.
if (this.TextMode == TextBoxMode.MultiLine)
{
if (this.MaxLength <= 0)
this.MaxLength = 200;
script = "return CountText(this,'" + this.MaxLength + "')";
}
As CountText
is bound to onKeryPress
, it overrides other scripts bind on the control with the keypress
event.
The following line of code binds the script with the onKeyPress
event.
this.Attributes.Add("onKeypress", script);
This code returns the errorMsg
associated with the textbox:
return errorMsg;
}
JavaScript functions
IntegerAndDecimal
This method allows to enter only integer and decimal data in the textbox control. If the isDecimal
value is true
, then it allows to enter decimal point values; otherwise, it allows to enter integer values only.
function IntegerAndDecimal(e,obj,isDecimal)
{
if ([e.keyCode||e.which]==8)
return true;
if ([e.keyCode||e.which]==46)
{
if(isDecimal=='true')
{
var val = obj.value;
if(val.indexOf(".") > -1)
{
e.returnValue = false;
return false;
}
return true;
}
else
{
e.returnValue = false;
return false;
}
}
if ([e.keyCode||e.which] < 48 || [e.keyCode||e.which] > 57)
e.preventDefault? e.preventDefault() : e.returnValue = false;
}
AlphaNumericOnly
This function allows to enter only alphabets or alphanumeric values in the textbox control. It checks if isAlphaonly
is true, then allows to enter only alphabets;otherwise, allows to enter alphanumeric values in the textbox control.
function AlphaNumericOnly(e,isAlphaonly)
{
var key = [e.keyCode||e.which];
var keychar = String.fromCharCode([e.keyCode||e.which]);
keychar = keychar.toLowerCase();
if(isAlphaonly=='true')
checkString="abcdefghijklmnopqrstuvwxyz";
else
checkString="abcdefghijklmnopqrstuvwxyz0123456789";
if ((key==null) || (key==0) || (key==8) ||
(key==9) || (key==13) || (key==27) )
return true;
else if (((checkString).indexOf(keychar) > -1))
return true;
else
return false;
}
keyup
This function shows and hides the error message associated with the textbox control when the textbox Required
property is set to true
. It also calls the showWaterMarkText
method if the ShowWaterMark
text attribute value is set to true
.
function keyup(cid)
{
var showWaterMark = $('#' + cid).attr("ShowWaterMark");
if (showWaterMark === "True")
test = watermark + $('#' + cid).attr("LabelValue");
else
test = '';
if ($('#' + cid).val() === '' || $('#' + cid).val() === test) {
document.getElementById('spError' + cid).style.display = 'block';
$('#' + cid).removeClass('normal');
$('#' + cid).addClass('mandatory');
}
else {
document.getElementById('spError' + cid).style.display = 'none';
$('#' + cid).removeClass('mandatory');
$('#' + cid).addClass('normal');
}
if (showWaterMark === "True")
showWaterMarkText(cid);
}
CountText
This function does not allow entering more characters than maxlimit
. Note: it's used only for multiline textboxes.
function CountText(field, maxlimit)
{
if (field.value.length < maxlimit)
{
return true;
}
else
return false;
}
checkReg
This function is to display the error message when data entered is not valid according to the custom pattern specified in the CustomPattern
property.
function checkReg(obj,pattern)
{
if(obj.value!=='' && pattern!=='')
{
var pattern1= new RegExp(pattern);
if(obj.value.match(pattern1))
{
document.getElementById('spCuError'+obj.id).style.display='none';
return true;
}
else
{
document.getElementById('spCuError'+obj.id).style.display='block';
return false;
}
}
}
callOnload
This function sets the style of the textbox to the mandatory CSS class when the Required
property is set to true
and no data can be entered by the user. It also calls the showWaterMark
function to show the watermark text in the textbox.
function callOnload()
{
$("input[isRequired=true]").each(
function(n)
{
$('#' +this.id).addClass('mandatory');
if(this.value==='')
{
$('#' +this.id).removeClass('normal');
$('#' +this.id).addClass('mandatory');
}
else
{
$('#' +this.id).removeClass('mandatory');
$('#' +this.id).addClass('normal');
}
}
);
$("textarea[isRequired=true]").each(
function(n)
{
$('#' +this.id).addClass('mandatory');
if(this.value==='')
{
$('#' +this.id).removeClass('normal');
$('#' +this.id).addClass('mandatory');
}
else
{
$('#' +this.id).removeClass('mandatory');
$('#' +this.id).addClass('normal');
}
}
);
showWaterMark();
}
showWaterMark
This function get called by callOnLoad method this function show watermarktext in textbox control when the ShowWaterMark attribute value is set to true.
var watermark = "";
function showWaterMark() {
$("input[ShowWaterMark=True]").each(
function(n) {
showWaterMarkText(this.id);
$('#' + this.id).focus(function() {
test = watermark + $('#' + this.id).attr("LabelValue");
if (this.value == test) {
this.value = "";
}
});
}
);
$("textarea[ShowWaterMark=True]").each(
function(n) {
showWaterMarkText(this.id);
$('#' + this.id).focus(function() {
test = watermark + $('#' + this.id).attr("LabelValue");
if (this.value == test) {
this.value = "";
}
});
}
);
}
showWaterMarkText
This function is called on onBlur event or form keyUp event. Function show watermarktext if the there is no value in textbox or value is equal to watermarktext, Otherwise it remove the watermark CSS values.
function showWaterMarkText(id) {
test = watermark + $('#' + id).attr("LabelValue");
if ($('#' + id).val() === ''
|| $('#' + id).val() == test
) {
$('#' + id).val(watermark + $('#' + id).attr("LabelValue"));
$('#' + id).css("color", "#999");
$('#' + id).css("font-style", "italic");
if(document.getElementById('spError' + id) !== null)
document.getElementById('spError' + id).style.display = 'none';
}
else {
$('#' + id).css("color", "#000");
$('#' + id).css("font-style", "");
}
}
validateFormInputs
The function attached with the button click which submits data to the server, but before that, it validates all the textbox controls having the groupid
which is passed in as a function parameter.
function validateFormInputs(gropId) {
var isAllValid = true;
var searchConditon = "";
if (gropId !== "" && gropId !== undefined) {
searchConditon = searchConditon +
"input[isRequired=true][GroupId=" + gropId + "]";
}
else {
searchConditon = searchConditon + "input[isRequired=true]";
}
$(searchConditon).each(
function(n) {
test = watermark + $('#' + this.id).attr("LabelValue");
if (this.value === '' || this.value == test)
isAllValid = false;
document.getElementById('spError' +
this.id).style.display = 'block';
}
else {
if (this.pattern !== '' && this.pattern !== undefined) {
if (!checkReg(this, this.pattern)) {
isAllValid = false;
}
}
if (document.getElementById('spError' + this.id) != null)
document.getElementById('spError' +
this.id).style.display = 'none';
}
}
);
searchConditon = "";
if (gropId !== "" && gropId !== undefined) {
searchConditon = searchConditon +
"textarea[isRequired=true][GroupId=" + gropId + "]";
}
else {
searchConditon = searchConditon + "textarea[isRequired=true]";
}
$(searchConditon).each(
function(n) {
test = watermark + $('#' + this.id).attr("LabelValue");
if (this.value === ''|| this.value == test)
isAllValid = false;
document.getElementById('spError' +
this.id).style.display = 'block';
}
else {
if (document.getElementById('spError' + this.id) != null)
document.getElementById('spError' +
this.id).style.display = 'none';
}
}
);
return isAllValid;
}
Note: You need to pass the group ID only when you have to validate the controls related to the given group, i.e., if there are two or more groups of the control validated by different buttons.
Advantages
- SQL injection attack
Because the control only allows to enter data specified in a property, it does not allow entering unwanted characters which creates problems when doing database DML operations. Read more about SQL injection attacks here: http://en.wikipedia.org/wiki/SQL_injection.
- Rendering cost decrease
It also decreases the cost of rendering. Because you attach the validation control itself on the page and also emit JavaScript if the EnableClient
property is set to true
.
- Multiple type of validation in one textbox control
By setting the ValidationType
property, we can apply more than one validation method, e.g., required + alpha, required + numeric etc.
- Watermark
If showWaterMark = true
, it allows to show a watermark in the textbox control, which can be used to show help text or a text value to enter in the textbox.
ReadOnly
Using this property, we can show the textbox as a label when the form is in read-only mode, i.e., in non-editable form just for viewing purposes.
How to use
Following is an implementation of the textbox control on a page. To get more information about this, download the code and check it out.
<form id="form1" runat="server">
<table>
<tr>
<td>
<cc:MyTextBox runat="server" id="MyTextBox2" GroupId="A"
AssociatedLableText="FirstName" DataType="requiredAndAlphaNumeric" >
</cc:MyTextBox>
</td>
<td>
<cc:MyTextBox runat="server" id="MyTextBox1" GroupId="A"
AssociatedLableText="LastName" DataType="requiredAndAlpha" >
</cc:MyTextBox>
</td>
<td>
<cc:MyTextBox runat="server" id="MyTextBox3" GroupId="B"
AssociatedLableText="Remark" TextMode="MultiLine"
DataType="required" ></cc:MyTextBox>
</td>
<td>
<cc:MyTextBox runat="server" id="MyTextBox4" GroupId="A"
AssociatedLableText="Email"
DataType="requiredCustom"
CustomPattern="([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+
\.([a-zA-Z])+([a-zA-Z])+" >
</cc:MyTextBox>
</td>
<td>
<cc:MyTextBox runat="server" id="MyTextBox5" AssociatedLableText="Test"
ShowWaterMark="true" WaterMarkText="TestBox" ></cc:MyTextBox>
</td>
</tr>
</table>
<cc:MyButton runat="server" ID="mybutton"
OnOnCustomCommand="mybutton_OnCustomCommand" CausesValidation="true"
OnClientClick="return validateFormInputs('A');" CommandArgument="" Text="test" />
</form>
Conclusion
This textbox control implementation provides a basic implementation of a custom control with the use of jQuery and JavaScript.