When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, October 31, 2007

Creating a TextBox Word / Character Counter Control

By Scott Mitchell


Introduction


When storing user-supplied text data into a database, it is essential that the length of the user's input does not exceed the size of the corresponding database table field. For example, imagine that you have defined a table with a field named Comments of type varchar(50). In a web page, the user is presented with a textbox into which to enter their comments. After doing so and clicking the "Save" button on the page, a postback ensues and the database is updated with the user's input. If the user entered more than 50 characters worth of comments, however, running the database UPDATE statement will result in an exception with the message: String or binary data would be truncated.

To prevent these types of exceptions, you need to ensure that the user's input does not exceed the size defined in the database. If it does, you must cancel the update and somehow alert the user that their input is too verbose. One way to proactively alert users that their input is too long is to interactively show them how many characters they've entered, along with how many maximum characters are allowed. This can be accomplished with a bit of client-side JavaScript code that runs whenever the user presses a key within the textboxes whose lengths you want to track and display.

In this article we'll look at a custom ASP.NET 2.0 server control I built named TextBoxCounter that uses JavaScript to display the total number of words and/or characters entered into a specified TextBox. The control's complete source code is available at the end of the article and you're welcome to use this control anyway you like (free of charge, of course). Read on to learn more!

- continued -

This article starts by examining how to use the TextBoxCounter control in an ASP.NET web page, which is as easy as dragging and dropping the control onto an ASP.NET page and setting a few properties. Next, we'll look at interesting portions of the control's source code. The article concludes with a discussion on possible enhancements.

Using the TextBoxCounter Control


The TextBoxCounter control is a free, open-source ASP.NET 2.0 custom control I built that is designed to interactively display the number of characters and/or words entered into a specific TextBox control. To get started using this control, download the ZIP at the end of this article. In addition to the code for the server controls, the ZIP file also includes an application that demonstrates the TextBoxCounter control in action.

The TextBoxCounter control is similar to ASP.NET's validation controls in that the TextBoxCounter control "points" to a single TextBox control just like the validation controls "point" to the control they are validating. With the validation controls you "point" to the the control to validate by specifying its ID in the validation control's ControlToValidate property. Likewise, with the TextBoxCounter you "point" to the TextBox whose characters or words you want to count via the TextBoxCounter control's TextBoxControlId property. That's all there is to it! There are other properties available, which we'll look at shortly, but the only property you must set is the TextBoxControlId property, and this property must be set to a TextBox's ID value.

Let's look at a very simple example. Create an ASP.NET page that prompts the visitor for their name. Add a TextBox Web control and set its ID property to Name. At this point your page's declarative markup should look like the following:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="TextBoxCounterDemo.aspx.vb" Inherits="TextBoxCounterDemo" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
   <form id="form1" runat="server">
   <div>
      Enter your name:

<asp:TextBox ID="Name" runat="server"></asp:TextBox>


   </div>
   </form>
</body>
</html>

Next, drag a TextBoxCounter from the Toolbox onto the page, immediately after the Name TextBox. If you do not see the TextBoxCounter control in your Toolbox, you can add it by right-clicking on the Toolbox, selecting the "Choose Items..." option from the context menu, and browsing to the skmControls2.dll assembly that is included in the download at the end of this article. This will add a <%@Register%> directive as well as the declarative markup for the TextBoxCounter control.

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="TextBoxCounterDemo.aspx.vb" Inherits="TextBoxCounterDemo" %>

<%@ Register Assembly="skmControls2" Namespace="skmControls2" TagPrefix="skm" %>



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
   <form id="form1" runat="server">
   <div>
      Enter your name: <asp:TextBox ID="Name" runat="server"></asp:TextBox>
      

<skm:TextBoxCounter runat="server" ID="TextBoxCounter1"></skm:TextBoxCounter>


   </div>
   </form>
</body>
</html>

Since we want to count the characters and words entered in the Name TextBox, set the TextBoxCounter control's TextBoxControlId property to "Name". You can do this by entering the property value in the declarative syntax or through the Properties window in the Designer.

Next, view the page in a browser. When the page is first visited the TextBoxCounter control displays the text "0 words, 0 characters". As you start to type in the textbox, however, the display automatically updates the words and character counts. The following screenshot shows the display after I've entered my name into the Name TextBox.

You can change the appearance of the TextBoxCounter through the standard WebControl style properties: Font, BackColor, ForeColor, BorderColor, Width, Height, and so on. To customize the display of the word and character count, use the DataFormatString property. In particular, enter whatever string you want to appear substituting the values "{0}" and "{1}" where you want the word and character counts to appear, respectively. The default value for DataFormatString is "{0} words, {1} characters". To display just the character count, for example, change this property to a value like: "You've entered {1} characters!"

The TextBoxCounter control also contains two read-only properties: Characters and Words. These properties are useful for determining the number of characters or words entered into the control's corresponding TextBox. For example, before updating the database you could first check to ensure that the input entered by the user did not exceed the character length imposed by the database column's defined size.

If TextBoxCounter1.Characters > 50 Then
   'TODO: Display message explaining problem...
Else
   'TODO: Update database...
End If

A Look at the TextBoxCounter Control's Code


The source code for the TextBoxCounter control is amazingly simple. Part of this simplicity is thanks to the power of inheritance. There TextBoxControl derives from the WebControl class and therefore inherits all of its base behavior.

The TextBoxCounter control includes the properties discussed above - TextBoxControlId, DataFormatString, and so on. I also added a protected method named GetTextBoxControl() that returns the TextBox control on the page that is referenced by the TextBoxControlId. If TextBoxControlId is not specified or a corresponding TextBox control cannot be found, an HttpException is thrown; otherwise the TextBox instance is retrieved via the FindControl(controlId) method and is returned.

protected virtual TextBox GetTextBoxControl()
{
   if (string.IsNullOrEmpty(this.TextBoxControlId))
      throw new HttpException(...);

   

TextBox tb = this.FindControl(this.TextBoxControlId) as TextBox;


   if (tb == null)
      throw new HttpException(...);

   

return tb;


}

The GetTextBoxControl() method is called anytime a reference to the TextBox is required.

I think all of the properties are fairly straightforward except for one: Words. Words, recall, returns the number of words entered into the TextBox. It does so by referencing the TextBox control's Text property and then using a regular expression to replace all space strings (which, in addition to the space character, includes tabs and carriage returns) with a single space. It then breaks up the string by spaces and counts the number of non-empty elements in the array:

public virtual int Words
{
   get
   {
      // Get the TextBox
      TextBox tb = GetTextBoxControl();
      
      // Replace any space character (\s) with a single space
      string uniformSpaces = Regex.Replace(tb.Text, "\\s", " ", RegexOptions.Compiled | RegexOptions.Multiline);
      
      // Split up the string on single spaces
      string[] pieces = uniformSpaces.Split(" ".ToCharArray());

      // Count how many non-empty array elements we have
      int wordCount = 0;
      for (int i = 0; i < pieces.Length; i++)
         if (pieces[i].Length > 0)
            wordCount++;

      return wordCount;
   }
}

The logic used for the Words property was taken from a JavaScript sample I found online that showed how to use JavaScript to count the number of words in a TextBox. That JavaScript sample, plus comments, can be found at: Counting Words.

The final method worth exploring in the TextBoxCounter control code is OnPreRender. OnPreRender is executed when the page enters the PreRender stage of its lifecycle, which is the time when controls are supposed to add any client-side JavaScript. The TextBoxCounter control uses JavaScript to interactively update the TextBoxCounter on the screen as the user enters text into the associated TextBox control.

protected override void OnPreRender(EventArgs e)
{
   base.OnPreRender(e);

   string treatCRasOneChar = "false";
   if (this.TreatCarriageReturnsAsOneCharacter)
      treatCRasOneChar = "true";

   // (1) Register the client-side function using WebResource.axd (if needed)
   // see: http://aspnet.4guysfromrolla.com/articles/080906-1.aspx
   if (this.Page != null && !this.Page.ClientScript.IsClientScriptIncludeRegistered(this.GetType(), "skmControls2"))
      this.Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "skmValidators", this.Page.ClientScript.GetWebResourceUrl(this.GetType(), "skmControls2.skmControls2.js"));


   // (2) Call skm_CountTextBox onkeyup
   TextBox tb = GetTextBoxControl();
   tb.Attributes["onkeyup"] += string.Format("skm_CountTextBox('{0}', '{1}', '{2}', {3});", tb.ClientID, this.ClientID, this.DataFormatString.Replace("'", "\\'"), treatCRasOneChar);


   // (3) Call skm_CountTextBox on page load
   Page.ClientScript.RegisterStartupScript(this.GetType(), System.Guid.NewGuid().ToString(), string.Format("skm_CountTextBox('{0}', '{1}', '{2}', {3});", tb.ClientID, this.ClientID, this.DataFormatString.Replace("'", "\\'"), treatCRasOneChar), true);
}

The method accomplishes three important tasks (marked (1), (2), and (3) in the comments above):

  1. Adds a JavaScript include to the file that contains the JavaScript function to count the words and characters for a given TextBox. The JavaScript include file is actually embedded in the skmControls2 assembly and can be accessed via WebResource.axd. In short, there is a JavaScript file defined in the Visual Studio project that gets embedded in the compiled DLL file when the project is built. The embedded resource can later be accessed through the ASP.NET application by visiting WebResource.axd. See Accessing Embedded Resources through a URL Using WebResource.axd for more information on this technique.

    The JavaScript include file contains a single method, skm_CountTextBox, which, when called, determines the characters and words in the specified textbox and displays that information in the specified HTML element using the specified data format string.
  2. Adds an attribute to the associated TextBox control so that whenever the client-side onkeyup event fires, the skm_CountTextBox function is called. In short, this updates the TextBoxCounter's display whenever a key is pressed in the control's associated TextBox.
  3. Injects a call to skm_CountTextBox when the page first loads. This ensures that when the page is first visited the TextBoxCounter control will be automatically updated to reflect the current words and characters in the TextBox. Without this call to skm_CountTextBox on the page load the TextBoxCounter wouldn't display the word and character count until after the user pressed a key in the associated textbox.

Future Enhancements...


Currently the TextBoxCounter control only displays the number of characters and/or words entered into a specific TextBox. In the Introduction I mentioned how this sort of control would be useful for proactively showing the user how many characters they had entered so far in a textbox where there is a limit on the number of allowable characters. In such a scenario, it would be more helpful if the TextBoxCounter displayed the number of characters remaining rather than the number of characters entered. That is, if the Name TextBox from our earlier example only permitted 20 characters, after entering "Scott Mitchell" the TextBoxCounter should display "6 characters remaining" instead of "14 characters entered".

Another nice feature would be to have the ability to modify the appearance of the TextBoxCounter based on the number of characters or words entered. For example, if only 20 characters are allowed, the TextBoxCounter character text might switch from black to red when there are less than 10% of the available characters left. These are just some ideas I have percolating in my head, and will have to wait until a future version of the control. If you have any other ideas you'd like to see in an updated version, please do not hesitate to let me know.

Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the Code Used in this Article


    Further Reading:


  • A JavaScript Function for Counting Words
  • Accessing Embedded Resources through a URL Using WebResource.axd


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article