Sunday, November 4, 2007

Single & Multiline TextBox with MaxLength Validation

After doing a bit of searching online I couldn't find an easy way to control the character length in a text box and a multi line text box. Plus the limit is defined by the schema of the table in a database. So I did what any developer would do with this problem. I used it as an excuse to write some code!

Here is one example of limiting characters in a text box or a multi line text box in a asp.net form. This example will also show how to add a dynamic warning message once the limit has been reached.

This example has 3 parts.

  • A Stored Procedure

  • Some C# code

  • A Javascript function



Lets get into the code!

Create the stored procedure

CREATE PROCEDURE [dbo].[GetFieldWidths]
(
@TableName nvarchar(40)
)
AS
BEGIN
SELECT COLUMN_NAME,
CHARACTER_MAXIMUM_LENGTH,
DATA_TYPE
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = @TableName
END
RETURN

Create a C# function to read all valid fields widths into a Generic Dictionary Collection.



// helper function
public static Dictionary FieldWidths
{
get
{
System.Web.HttpApplicationState ApplicationState = HttpContext.Current.Application;
if (ApplicationState["cDatabase.Tables.tblUsers.FieldWidths"] == null)
{
ApplicationState["cDatabase.Tables.tblUsers.FieldWidths"] = cDbaseFunc.FieldWidths(tblUsers.TableName);
}

return ApplicationState["cDatabase.Tables.tblUsers.FieldWidths"] as Dictionary;
}
}

// main function
public static Dictionary FieldWidths(string Table)
{
//Load field types
string[] aryStringTypes = new string[6] { "char", "nchar", "ntext", "nvarchar", "text", "varchar" };
List StringTypes = new List(aryStringTypes);

Database db = DatabaseFactory.CreateDatabase();
DbCommand dbCommand = db.GetStoredProcCommand(cDatabase.StoredProcedure.GetFieldWidths);
db.AddInParameter(dbCommand, "@TableName", DbType.String, Table);
IDataReader dr = db.ExecuteReader(dbCommand);

string FieldName = string.Empty;
int FieldLength;
string FieldType = string.Empty;

Dictionary FW = new Dictionary();
while (dr.Read())
{
FieldType = dr.GetString(2).ToLower();
if (StringTypes.Contains(FieldType))
{
FieldName = dr.GetString(0);
FieldLength = dr.GetInt32(1);
FW.Add(FieldName, FieldLength);
}
}
dr.Close();

return FW;
}

Create the Javascript function that limits the characters and creates the dynamic message.



function CheckCharMaxLenLimit(control,maxlength)
{
var ErrorMsgID = control.id + "_$MAXLENGTH_ERROR_MSG$";
var ErrorMsg = document.getElementById(ErrorMsgID);

var MaxLength;
if(maxlength != null)
{
MaxLength = maxlength;
}
else
MaxLength = control.maxLength - 1;

var TextLength = control.value.length;
if(TextLength > MaxLength)
{
control.value = control.value.substring(0,MaxLength);

if(ErrorMsg == null)
{
control.outerHTML = control.outerHTML + MaxLength + " character limit!";
}
}
else
{
if(ErrorMsg != null)
ErrorMsg.parentNode.removeChild(ErrorMsg);
}
}

The final step is too attach the javascript function to your text box control "onkeyup" event.
You can do this in the code behind like so....
this.txtUserName.Attributes["onkeyup"] = "CheckCharMaxLenLimit(this," + this.FieldWidths["Username"] + ");";

Summary


The nice thing about the C# function is that it caches the returning list of fields and widths into an Application State variable. If your tables schema changes allot you could always cache it in a session state variable. This reduces the hits to SQL server which improves performance.

The character limiting and checking is handled on the client side using the javascript function. This function also supports the "maxLength" attribute of the text box control. The dynamic message is also created on the client side by using the DOM to attach a child element to the text box. This creates a very quick UI response. Lastly the dynamic message can be formatted using standard CSS.

Like so...
.MAXLENGTH_ERROR_MSG
{
color:red;
}

This method uses SQL2005 but I'm sure it could easily be used with any database platform. I hope this helps someone out there with the same problem.

1 comment:

Anonymous said...

What USING clause?
VS2005 insists :-

Using the generic type 'System.Collections
.Generic.Dictionary<TKey,TValue>'

requires '2' type arguments

robin at technolibrium dot co dot za