char counter

Ext JS – A (very simple) email form with character counter

This super simple email form is for when the email recipients are already known and cannot be changed on the email form. I worked out two things I want to remember on this form – created a “tip” to expand the contents of an input field and also have a “amount of chars remaining” counter updating on the form. The counter shows the number of chars remaining and then when the limit is reached, the Ext JS validation “msg” text is shown. Here are some pictures (condensed).

Note: Ext JS 4 version at https://gist.github.com/aghuddleston/5357858.

Now the code snippets of the interesting parts. This is condensed a bit. The formpanel is in an Ext JS window, that I extended. The code for that is not here, but all the important bits and pieces should be.


	// snip
		new Ext.form.FormPanel({
			labelWidth: 167,
			defaultType: 'displayfield',
			baseCls: 'x-plain',
			itemId: 'emailform',
			items: [
				{
					xtype: 'container',
					layout: 'form',
					labelWidth: 55,
					anchor: '100%',
					items: {
						xtype: 'trigger',
						itemId: 'sendto',
						ref: '../../sendto',
						fieldLabel: 'Send To',
						value: this.getSendTos(),
						// name: 'to',
						submitValue: false,
						anchor: '-5',
						editable: false,
						scope: this,
						onTriggerClick : this.onSendToClick.createDelegate(this)
					}
				},
				{
					id: 'emailbody',
					itemId: 'emailbody',
					xtype: 'textarea',
					hideLabel: true,
					name: 'message',
					msgTarget: 'under',
					maxLength: 2000,
					anchor: '-5 -53',
					enableKeyEvents: true,
					listeners : {
						scope : this,
						keydown: this.updateTextCtr,
						keyup: this.updateTextCtr,
						focus: this.closeSendToTip
					}
				},
				{
					xtype: 'displayfield',
					itemId: 'textCtr',
					fieldLabel: 'Allowed characters remaining',
					hideParent: true,
					anchor: '-10'
				} 
			]
		});
	// snip

	buildSendToTip : function () {
		return new Ext.Tip({
			html: this.getSendTos(),
			closable: true,
			width: 400 // initial width needed to make the sizing work
		});
	},

	closeSendToTip : function () {
		if (this.sendToTip.isVisible()) {
			this.sendToTip.hide();
		}
	},
	
	/**
	 * When the user clicks in the send to box, pop open a tooltip that
	 * shows the complete list of the user ids this email is going to.
	 * The tip should cover the send to trigger field, right aligining
	 * with it, up to a maximum of 500px.
	 */
	onSendToClick : function (event) {
		var width = this.sendto.getWidth(),
			position = this.sendto.getPosition(),
			xpos;
		
		// Figure out how wide the tip should be, the max is 500
		if (width > 500) {
			xpos = position[0] + (width - 500);
			position[0] = xpos;
			width = 500;
		}
		
		this.sendToTip.setWidth(width);
		this.sendToTip.doLayout();
		this.sendToTip.showAt(position);
	},


	/**
	 * Update the 'Allowed chars remaining' text as the user types. Once the
	 * limit is reached, the Ext validation tip will display under the 
	 * text area and the allowed char remaining field will be hidden.
	*/
	updateTextCtr : function (body, event) {
		var form = this.getComponent('emailform'),
			ctr = form.getComponent('textCtr'),
			ctrEl = ctr.getEl(),
			text = body.getValue(),
			maxLength = body.maxLength;
			
		if (text.length > maxLength) {
			ctr.hide();
			ctrEl.up('.x-form-item').setDisplayed(false);
		} else {
			if (!ctr.isVisible()) {
				ctr.show();
				ctrEl.up('.x-form-item').setDisplayed(true);
			}
			ctr.setValue(maxLength - text.length);
		}
	}

	// extraInit is called on the window show event 
	extraInit : function () {
		var form = this.getComponent('emailform'),
			body = form.getComponent('emailbody'),
			ctr = form.getComponent('textCtr');
		
		ctr.setValue(body.maxLength);
	}

	// also destroying the tip on the window destroy event