In ASP.NET, you can create a textarea by adding a multiline textbox to your markup:
<asp:textbox id="textboxDescription" runat="server" textmode="MultiLine" />
Intuitively, we started adding the MaxLength property to this, in order to let the content of the textarea match the length of our database column:
<asp:textbox id="textboxDescription" runat="server" textmode="MultiLine" maxlength="2000" />
If you’re reading this, you know that doesn’t work. We, however didn’t. This is easily fixed with some javascript. But if you have a large site with many of these mistakes, you’d want to do it in one go. Use a control adapter for this:
Public Class TextBoxAdapter
Inherits WebControlAdapter
' If you need to access the adapted control, the framework advises to expose
' a private method encapsulating the Adapter's Control property.
' We can cast it without doing any test, as by naming convention,
' this adapter shall only be used for adapting Textboxes (or derived types)
Private ReadOnly Property TextBoxControl() As TextBox
Get
Return DirectCast(MyBase.Control, TextBox)
End Get
End Property
Protected Overrides Sub RenderBeginTag(ByVal writer As System.Web.UI.HtmlTextWriter)
If TextBoxControl.TextMode = TextBoxMode.MultiLine AndAlso TextBoxControl.MaxLength > 0 Then
writer.AddAttribute("maxlength", TextBoxControl.MaxLength.ToString)
End If
MyBase.RenderBeginTag(writer)
End Sub
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
RenderBeginTag(writer)
If TextBoxControl.TextMode = TextBoxMode.MultiLine Then
HttpUtility.HtmlEncode(TextBoxControl.Text, writer)
Else
MyBase.RenderContents(writer)
End If
MyBase.RenderEndTag(writer)
End Sub
End Class
Due to a bug in the WebControlAdapter class, you have to override the Render method.
Now, add an App_Browsers ASP.NET folder to your project, and add an Allbrowsers.browser file to the folder:
<browsers> <browser refID="Default"> <controlAdapters> <adapter controlType="System.Web.UI.WebControls.TextBox" adapterType="Ihc.Cpd.Presentation.Globals.TextBoxAdapter" /> </controlAdapters> </browser> </browsers>
Finally, include some javascript to your project. We’ve put it in a seperate file, which is always loaded (this needs jQuery, and was based on other peoples code, but I’ve lost the links):
// ignore these keys
var ignore = [8, 9, 13, 33, 34, 35, 36, 37, 38, 39, 40, 46];
// use keypress instead of keydown as that's the only place keystrokes could be canceled in Opera
// handle textareas with maxlength attribute
$('textarea[maxlength]').live('keypress',
function(event) {
// this is where the magic happens
var self = $(this),
maxlength = self.attr('maxlength'),
code = $.data(this, 'keycode');
// check if maxlength has a value.
// The value must be greater than 0
if (maxlength && maxlength > 0) {
// continue with this keystroke if maxlength
// not reached or one of the ignored keys were pressed.
if (self.val().length >= maxlength || $.inArray(code, ignore) !== -1) {
alert('Too long!');
return false;
}
else
return true;
}
})
.live('keydown',
function(event) {
// store keyCode from keydown event for later use
$.data(this, 'keycode', event.keyCode || event.which);
})
.live('keyup',
function(event) {
// cut long text if pasted in the textarea
var self = $(this),
maxlength = self.attr('maxlength'),
text = self.val();
if (text.length > maxlength)
{
alert('Too long!');
self.val(text.substr(0, maxlength));
}
});
Now, what does that learn us? First, that we didn’t test this good enough. Second, a schemaless database like RavenDb has the advantage over relational databases. That’s why I’m switching from NHibernate to RavenDb for my own project.