Jun
17
2010

AJAX Username Availability Checker Using MooTools

The HTML

1<p><strong>Please provide your desired username: &nbsp;&nbsp;&nbsp;</strong>
2 <input type=”text” name=”username” id=”username” size=”30″ class=”basis” />
3</p>

The foundation of the system is the INPUT element with a specific ID. No other elements are required. The eventual IMG element will be generated by MooTools.

The CSS

.basis		{ padding:5px; border:1px solid #ccc; }
.available	{ border:1px solid #008000; background:#90ee90; }
.taken		{ border:1px solid #fc0; background:#fffea1; }
1.basis { padding:5px; border:1px solid #ccc; }
2.available { border:1px solid #008000; background:#90ee90; }
3.taken { border:1px solid #fc0; background:#fffea1; }

You’ll want to create three CSS classes: one that is always applied to the input, another class which represents an available username, and one last class to represent a taken username. Green is always good to use for positive results. As for how you denote a taken username, please don’t be a #f00.

The MooTools JavaScript

var AvailabilityChecker = new Class({

	//implements
	Implements: [Options,Events],

	//options
	options: {
		trigger: 'keyup',
		offset: { x:0, y:0 },
		minLength: 5,
		availableClass: 'available',
		takenClass: 'taken',
		availableImage: '',
		takenImage: '',
		url: 'ajax-username-check.php'
	},

	//initialization
	initialize: function(element,options) {
		//set options
		this.setOptions(options);
		this.element = document.id(element);
		this.lastValue = this.element.value;
		this.cache = {};
		//create the image which will display to the side
		var pos = this.element.getCoordinates();
		this.image = new Element('img',{
			src: '',
			styles: {
				'z-index': 100000,
				position: 'absolute',
				top: pos.top + this.options.offset.y,
				left: pos.left + pos.width + this.options.offset.x
			}
		}).inject(document.body);
		//workers and removers
		this.comparer = function(response) {
			this.cache[this.element.value] = response;
			var state = (response == '1') ? 'available' : 'taken';
			this.element.addClass(this.options[state + 'Class']);
			this.image.set('src',this.options[state + 'Image']);
			return state;
		};
		this.remover = function() {
			this.element.removeClass(this.options.availableClass).removeClass(this.options.takenClass);
		};
		//create the request which will be frequently used
		this.request = new Request({
			url: this.options.url,
			method: 'get',
			link: 'cancel',
			onRequest: this.remover.bind(this),
			onComplete: this.comparer.bind(this)
		});
		//add listener
		this.element.addEvent(this.options.trigger,function() {
			var value = this.element.value;
			if(value.length >= this.options.minLength && value != this.lastValue) {
				this.validate(this.lastValue = value);
			}
		}.bind(this));
	},

	//a method that does whatever you want
	validate: function(value) {
		this.fireEvent('check');
		if(this.cache[value] != undefined) {
			return this.comparer(this.cache[value]);
		}
		else {
			return this.request.send('username=' + value + '&ajax=1');
		}
		return this;
	}

});

//USAGE!
window.addEvent('domready', function() {
	var validator = new AvailabilityChecker('username',{
		trigger: 'keyup',
		availableImage: 'checkmark.jpg',
		takenImage: 'warning.jpg',
		offset: { x: 4, y: 4 },
		minLength: 4,
		url: '<?php echo $_SERVER["PHP_SELF"]; ?>'
	});
});
1var AvailabilityChecker = new Class({
2
3 //implements
4 Implements: [Options,Events],
5
6 //options
7 options: {
8 trigger: ‘keyup’,
9 offset: { x:0, y:0 },
10 minLength: 5,
11 availableClass: ‘available’,
12 takenClass: ‘taken’,
13 availableImage: ”,
14 takenImage: ”,
15 url: ‘ajax-username-check.php’
16 },
17
18 //initialization
19 initialize: function(element,options) {
20 //set options
21 this.setOptions(options);
22 this.element = document.id(element);
23 this.lastValue = this.element.value;
24 this.cache = {};
25 //create the image which will display to the side
26 var pos = this.element.getCoordinates();
27 this.image = new Element(‘img’,{
28 src: ”,
29 styles: {
30 ‘z-index’: 100000,
31 position: ‘absolute’,
32 top: pos.top + this.options.offset.y,
33 left: pos.left + pos.width + this.options.offset.x
34 }
35 }).inject(document.body);
36 //workers and removers
37 this.comparer = function(response) {
38 this.cache[this.element.value] = response;
39 var state = (response == ’1′) ? ‘available’ : ‘taken’;
40 this.element.addClass(this.options[state + 'Class']);
41 this.image.set(‘src’,this.options[state + 'Image']);
42 return state;
43 };
44 this.remover = function() {
45 this.element.removeClass(this.options.availableClass).removeClass(this.options.takenClass);
46 };
47 //create the request which will be frequently used
48 this.request = new Request({
49 url: this.options.url,
50 method: ‘get’,
51 link: ‘cancel’,
52 onRequest: this.remover.bind(this),
53 onComplete: this.comparer.bind(this)
54 });
55 //add listener
56 this.element.addEvent(this.options.trigger,function() {
57 var value = this.element.value;
58 if(value.length >= this.options.minLength && value != this.lastValue) {
59 this.validate(this.lastValue = value);
60 }
61 }.bind(this));
62 },
63
64 //a method that does whatever you want
65 validate: function(value) {
66 this.fireEvent(‘check’);
67 if(this.cache[value] != undefined) {
68 return this.comparer(this.cache[value]);
69 }
70 else {
71 return this.request.send(‘username=’ + value + ‘&ajax=1′);
72 }
73 return this;
74 }
75
76});
77
78//USAGE!
79window.addEvent(‘domready’, function() {
80 var validator = new AvailabilityChecker(‘username’,{
81 trigger: ‘keyup’,
82 availableImage: ‘checkmark.jpg’,
83 takenImage: ‘warning.jpg’,
84 offset: { x: 4, y: 4 },
85 minLength: 4,
86 url: ‘<?php echo $_SERVER["PHP_SELF"]; ?>’
87 });
88});

The original class featured a host of problems. No element was required, a new Request was being generated every keystroke, results weren’t cached. Ugh. Those have all been fixed and I’ve added event functionality to the class. I’ve also implemented many new MooTools best practices.

Leave a comment