We have all run into this one. You use a TextArea, or a TextBox with MultiLine set to True, so the user can enter a long description or comments. The problem is that the MaxLength attribute you are used to relying on for a standard TextBox does not work when MultiLine is True.
There are a few ways to handle it. I have dropped in a line or two of JavaScript with onkeypress events to count characters and stop the user at the limit. That works, but it means copying the JavaScript to the right pages and wiring up the event for every control you want to limit. A better approach is to extend the System.Web.UI.WebControls.TextBox control itself:
public class TextArea : System.Web.UI.WebControls.TextBox
{
protected override void OnPreRender(EventArgs e)
{
if (MaxLength > 0 && TextMode == System.Web.UI.WebControls.TextBoxMode.MultiLine)
{
// add javascript handlers for paste and keypress
Attributes.Add("onkeypress", "doKeypress(this);");
Attributes.Add("onbeforepaste", "doBeforePaste(this);");
Attributes.Add("onpaste", "doPaste(this);");
// expose maxlength to the client side
Attributes.Add("maxLength", MaxLength.ToString());
// register the client side include, only once per page
if (!Page.ClientScript.IsClientScriptIncludeRegistered("TextArea"))
{
Page.ClientScript.RegisterClientScriptInclude("TextArea",
ResolveClientUrl("~/Common/TextArea.js"));
}
}
base.OnPreRender(e);
}
}
The important part is how it attaches the onkeypress, onbeforepaste, and onpaste handlers, and registers the script include once per page. That keeps the JavaScript centralized in one file instead of scattered across every page that needs it.
Here is TextArea.js:
// keep the user from entering more than maxLength characters
function doKeypress(control)
{
maxLength = control.attributes["maxLength"].value;
value = control.value;
if (maxLength && value.length > maxLength - 1)
{
event.returnValue = false;
maxLength = parseInt(maxLength);
}
}
// cancel default behavior
function doBeforePaste(control)
{
maxLength = control.attributes["maxLength"].value;
if (maxLength)
{
event.returnValue = false;
}
}
// cancel default behavior and handle the paste ourselves
function doPaste(control)
{
maxLength = control.attributes["maxLength"].value;
value = control.value;
if (maxLength)
{
event.returnValue = false;
maxLength = parseInt(maxLength);
var oTR = control.document.selection.createRange();
var iInsertLength = maxLength - value.length + oTR.text.length;
var sData = window.clipboardData.getData("Text").substr(0, iInsertLength);
oTR.text = sData;
}
}
Register the control on your page:
<%@ Register TagPrefix="WebControls" Namespace="Test.WebControls" Assembly="Test.WebControls" %>
And then use it:
<WebControls:TextArea ID="txtTest" TextMode="MultiLine" MaxLength="500"
Rows="10" Columns="75" runat="server" />
The value you give MaxLength determines how many characters the user can enter. And of course the user can disable JavaScript, so validate on the server side as well.
One note from the present day: this post is from 2007, and the problem it solves no longer exists. HTML5 added native maxlength support to the textarea element, so on any current browser a plain <textarea maxlength="500"> enforces the limit for you. The JavaScript above also relies on Internet Explorer specific APIs, window.clipboardData and document.selection, which modern browsers no longer support. Server side validation is still worth doing, for the same reason it always was.