Textarea Maxlength is one of the eight example scripts in the book.
I added a simple script to the comment textareas in my blog that count the characters the user has typed in. I used this script as an example in my JavaScript Triggers article; now the time has come to publish the complete script.
See any blog entry for a working example of the script.
The purpose of my script is not to enforce the maximum length, though it can easily be changed to
do that. However, I decided to restrict my script to giving a polite reminder when the user exceeds the
maximum amount of characters. Actually enforcing this maximum length is left to the trim_to
attribute of Movable Type, which, being a server side functionality, is impossible for users to turn off.
As I explained in my article I want to use a custom attribute to carry the maxlength information. The
existence of the maxlength attribute triggers the assignment of an event handling script, and the
value of the attribute gives the maximum length the value of the textarea should have.
I added a maxlength attribute to all textareas that should have a maximum length:
<textarea id="text" name="text" maxlength="1250"></textarea>
This is the complete script. Call setMaxLength() onload, and enjoy the effect.
function setMaxLength() {
var x = document.getElementsByTagName('textarea');
var counter = document.createElement('div');
counter.className = 'counter';
for (var i=0;i<x.length;i++) {
if (x[i].getAttribute('maxlength')) {
var counterClone = counter.cloneNode(true);
counterClone.relatedElement = x[i];
counterClone.innerHTML = '<span>0</span>/'+x[i].getAttribute('maxlength');
x[i].parentNode.insertBefore(counterClone,x[i].nextSibling);
x[i].relatedElement = counterClone.getElementsByTagName('span')[0];
x[i].onkeyup = x[i].onchange = checkMaxLength;
x[i].onkeyup();
}
}
}
function checkMaxLength() {
var maxLength = this.getAttribute('maxlength');
var currentLength = this.value.length;
if (currentLength > maxLength)
this.relatedElement.className = 'toomuch';
else
this.relatedElement.className = '';
this.relatedElement.firstChild.nodeValue = currentLength;
// not innerHTML
}
Although on my site the maxlength is only enforced on one comment textarea on the entry and comment preview pages, and the maxlength value is always 1250, I wrote the script so that it can accomodate any number of textareas with any maxlength value. Therefore my script has become slightly more complicated than necessary, but it can be deployed in any situation.
The setMaxLength() function is called onload. It starts by gathering all textareas in the document.
function setMaxLength() {
var x = document.getElementsByTagName('textarea');
Then it creates the visible counter for the user. I create it once and clone it as often as necessary. The HTML structure is:
<div class="counter"><span>0</span>/1250</div>
When the users type in their comments, the content of the <span> changes.
I create the div and give it a class. I append the content later, because I need the actual maxlength of every individual textarea, something the script cannot yet know.
var counter = document.createElement('div');
counter.className = 'counter';
Then I loop through all textareas, and if I find a textarea with a maxlength attribute
I start doing things.
for (var i=0;i<x.length;i++) {
if (x[i].getAttribute('maxlength')) {
First of all I clone the counter. Then I set its innerHTML to "<span>0</span>/maxlength", reading out the maxlength from the attribute.
var counterClone = counter.cloneNode(true);
counterClone.innerHTML = '<span>0</span>/'+x[i].getAttribute('maxlength');
I insert the newly created clone after the textarea it applies to.
x[i].parentNode.insertBefore(counterClone,x[i].nextSibling);
Then I create a custom JavaScript property relatedElement for the textarea and point it
to the <span> in the counter. This allows me to easily access the <span>
later on.
x[i].relatedElement = counterClone.getElementsByTagName('span')[0];
I set the checkMaxLength as keyup and change event handler; I'll explain the double
event below.
x[i].onkeyup = x[i].onchange = checkMaxLength;
Finally I execute the event handler. This is for the comment preview pages: the textarea there already contains a comment, and the user should see the length of the comment.
x[i].onkeyup(); } } }
The checkMaxLength() function is called every time a user enters text. It starts by reading
out the maximum length from the maxlength attribute of the textarea, and the actual current
length of the text.
function checkMaxLength() {
var maxLength = this.getAttribute('maxlength');
var currentLength = this.value.length;
Then for the error messages. As I said above I didn't want the script to enforce the maxlength. First of
all anyone can turn off JavaScript and thus avoid my script. Secondly I can imagine people that write a lengthy
comment, then find out it's too long and subsequently edit it. This editing process should not be hindered by
an essentially arbitrary trimming of the text. I leave the actual trimming to Movable Type's trim_to
attribute and only create a polite reminder when the user enters too many characters.
I created a class toomuch which makes the <span> that contains the number
of characters the user has entered red and bold. When the current length exceeds the maximum length the
<span> gets this class, when it is equal or less than the maximum length the <span>
loses this class.
if (currentLength > maxLength) this.relatedElement.className = 'toomuch'; else this.relatedElement.className = '';
Instead of changing the className you could also set the length of the textarea content to the maximum length:
if (currentLength > maxLength) this.value.length = maxLength;
Finally I write the new length of the comment to the <span>:
this.relatedElement.firstChild.nodeValue = currentLength; }
One oddity here: originally I wanted to use this.relatedElement.innerHTML, but Explorer gave
an unknown runtime error. I don't know what causes it; I created a simple test that writes to the innerHTML
of a generated element, and Explorer didn't have any trouble with that test. So I leave this problem as
an exercise to the reader. Replace firstChild.nodeValue by innerHTML and try
to solve the bug.
As you've seen the checkMaxLength() function is triggered by the keyup and the change events.
The keyup event is fairly self-explanatory: when the user types a character, run the event handler. Note, however,
that I do not use the keypress event, because it fires before the character has been added
to the textarea. That's not what I want: I first allow the user to do anything he likes, and I check it only afterwards.
I added the change event for rarer cases. Occasionally I myself first write a comment in Textpad and when I'm happy with it I copy-paste it to the comment textarea. In this case I don't press a key (or rather, I don't have to press a key), and the script wouldn't run. Adding the change event solves that: the script also runs when the content of the textarea has been changed by other means than pressing a key.