Counter Textarea Dojo widget

On February 22, 2014, in Javascript, by Anuj Gakhar

There are probably hundreds of examples of textarea counter plugins out there (most of them jQuery though, but I wanted to write one in Dojo. The idea is quite simple, you want a textarea that takes a maxlength parameter and displays a counter of what’s available and does not let you enter more characters than that.

Dojo makes it really easy to write such a widget. Dojo already has something called a SimpleTextarea which is mostly a thin wrapper over the browser’s native textarea element. We can write a custom widget that extends the SimpleTextarea widget and set it’s “intermediateChanges” property to true which would make the textarea fire an onChange event whenever the contents of the textarea changes, which is exactly what we want it to do.

The benefit of using Dojo here is that it provides a cross-browser way to limit the textarea contents based on the maxlength attribute. Here is a working demo for the widget and below is the code for the custom textarea widget. Also available as a Gist if someone wants to clone/refactor.

define([
	"dojo/_base/declare",
	"dojo/_base/lang",
	"dojo/on",
	"dojo/dom-construct",
	"dojo/dom-style",
	'dijit/form/SimpleTextarea',
	"dijit/_WidgetBase"
], function (
	declare, 
	lang, 
	on, 
	domConstruct,
	domStyle,
	SimpleTextarea, 
	_WidgetBase
) {
	return declare('counterTextArea', [SimpleTextarea, _WidgetBase], {
		intermediateChanges: true,
		maxCharsAllowed: 100,
		counterNode: null,
		counterNodeTemplate: '<span style="font-size: 11px; clear: both; margin-top: 3px; display: block;" id="textarea-counter"></span>',
		counterHTML: '{usedChars} / {allowedChars}',
		startup: function () {
			this.inherited(arguments);

			if (this.maxLength) {
				this.maxCharsAllowed = parseInt(this.maxLength, 10);
			} else {
				this.maxLength = this.maxCharsAllowed;
			}

			this.counterNode = domConstruct.place(this.counterNodeTemplate, this.domNode, "after");

			dojo.connect(this, 'onChange', lang.hitch(this, this._process));

			this._process();
		},
		_process: function (value) {
			var val = value !== undefined ? value.length : this.value.length;
			this._onInput();
			this._updateCounter(val);
		},
		_updateCounter: function (val) {
			if (!this.counterNode) {
				return;
			}

			this.counterNode.innerHTML = lang.replace(this.counterHTML, {
				usedChars: val,
				allowedChars: this.maxCharsAllowed
			})

			if (val >= this.maxCharsAllowed) {
				domStyle.set(this.counterNode, 'color', 'red');
			} else {
				domStyle.set(this.counterNode, 'color', 'black');
			}
		}
	})
})

And here is how you can use this widget (assuming both the .js and .html are in the same folder)

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.2/dijit/themes/claro/claro.css"/>
	<script>dojoConfig = {parseOnLoad: true}</script>
	<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"></script>
</head>

<body class="claro" style="margin:0px auto; padding:50px;">
    <form>
        <textarea data-dojo-type='counterTextArea' 
        style="width:300px; height:100px;" maxlength="500"></textarea>
    </form>
    
    <script>
    require([
        "./counterTextArea.js", 
        "dojo/domReady!"
    ], function (counterTextArea) {
        
    });
    </script> 
</body>
</html>

I have tested this in IE8, 9 and 10, Chrome, Firefox and Safari and it seems to work for all of these browsers. You can paste data, write data, delete data and it still seems to work.

Tagged with:  

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 445 other subscribers

© 2011 Anuj Gakhar
%d bloggers like this: