MooTools Class Creation Tips

By  on  

Writing MooTools classes can be a daunting task, even for a novice MooTools developer. Here are a few tips I've picked up along the way that will take your Moo plugin / class development to the next level.

self = this

Using the this keyword is essential in MooTools but can become annoying when you need to use binding frequently. For example:

/* dreadful use of bind instead of "self" */

//more class code above
},
someMethod: function() {
	
	this.elements.each(function(element) {
		if(element.value == this.options.defaultValue) {
			element.set('value','');
		}
	},this);
	
	var request = new Request({
		method: 'get',
		url: 'page.php',
		data: {
			ajax: 1
		},
		onRequest: function() {
			this.options.textIndicator.set('text','Updating ' + this.elements.length + ' element...');
		}.bind(this),
		onSuccess: function() {
			this.options.textIndicator.set('text','Update successful. ' + this.elements.length + ' elements updated.');
		}.bind(this),
		onFailure: function() {
			this.options.textIndicator.set('text','Failed to update ' + this.elements.length + ' elements.');
		}.bind(this)
	}).send();
	
},
//more class code below

Instead of binding everything under the sun, set a self var that is equal to the this to avoid that mess:

/* better */
//more class code above
},
someMethod: function() {
	
	var self = this;
	
	self.elements.each(function(element) {
		if(element.value == self.options.defaultValue) {
			element.set('value','');
		}
	});
	
	var request = new Request({
		method: 'get',
		url: 'page.php',
		data: {
			ajax: 1
		},
		onRequest: function() {
			self.options.textIndicator.set('text','Updating ' + self.elements.length + ' element...');
		},
		onSuccess: function() {
			self.options.textIndicator.set('text','Update successful. ' + self.elements.length + ' elements updated.');
		},
		onFailure: function() {
			self.options.textIndicator.set('text','Failed to update ' + self.elements.length + ' elements.');
		}
	}).send();
	
},
//more class code below

Classes that use self references include Function, Native, and Swiff.

this.____ = $(this.options.element);

Modifying the class options from inside the class is generally poor practice. Instead of this:

this.options.element = $(this.target.element);

...use this:

this.element = $(this.target.element);

Your class will become shorter and you may accept both strings and Elements as values.

No $/$$ as Default Values

Since your MooTools class is likely not inside the domready() function, assigning default setting values to $('something') or $$('.somethings) is not wise:

var myClass = new Class({
	Implements: [Options],

	options: {
		elements: $$('a')
	},
	initialize: function() {
	
	},
	//more down here
});

Instead, set them to a string and extend the elements inside the initialize() method:

var myClass = new Class({
	Implements: [Options],

	options: {
		elements: 'a'
	},
	initialize: function() {
		this.elements: $$(this.options.elements);
	},
	//more down here
});

Step Back: Less Specificity

When creating a MooTools class, take a step back and think "what can I take out of this class to make it more flexible?" The less specific a plugin is, the more flexible and usable the class can be. For that specific use, extend your scaled-back class.

Less Dependencies, More Use

One advantage of using MooTools is that it's highly extensible. While MooTools implements numerous helper functions on native JavaScript objects, if you can avoid using the functionality of another MooTools class that's only use a few times, do it. Less dependencies can make your class more stable and modular.

Hopefully this list of tips can make your future plugin creation more fruitful, clean, and functional!

Recent Features

  • By
    fetch API

    One of the worst kept secrets about AJAX on the web is that the underlying API for it, XMLHttpRequest, wasn't really made for what we've been using it for.  We've done well to create elegant APIs around XHR but we know we can do better.  Our effort to...

  • By
    5 HTML5 APIs You Didn’t Know Existed

    When you say or read "HTML5", you half expect exotic dancers and unicorns to walk into the room to the tune of "I'm Sexy and I Know It."  Can you blame us though?  We watched the fundamental APIs stagnate for so long that a basic feature...

Incredible Demos

  • By
    JavaScript Canvas Image Conversion

    At last week's Mozilla WebDev Offsite, we all spent half of the last day hacking on our future Mozilla Marketplace app. One mobile app that recently got a lot of attention was Instagram, which sold to Facebook for the bat shit crazy price of one...

  • By
    HTML5 Input Types Alternative

    As you may know, HTML5 has introduced several new input types: number, date, color, range, etc. The question is: should you start using these controls or not? As much as I want to say "Yes", I think they are not yet ready for any real life...

Discussion

  1. Thanks, this is quite useful. I find that davidwalsh.name has almost become the defacto mootools site ;)

  2. David,

    those are some great tips! I just found myself in a situation when writing a class where I used bind(this) but also needed to reference the element returned in the .each loop. Using self would have really made that easier.

  3. Good tips. I like the “self” idea, but it seems like “self” could be a bad choice of names since it could be confused with the self/window object. I’ve seen other people use a variable called “that” instead. As long as it’s declared with the var keyword, it shouldn’t be a problem, but it’s still potentially confusing.

  4. var that = this;

    :D

  5. While this is very useful, keep in mind, that you only should use this where you need it, so on the first level, ‘outside’ an inner function using self in unnecessary.

  6. So what’s the best choice of doing things?
    – using bind (or the Binds mutator)
    or …
    – self (with the additional bonus you have access to “this” too)?

    The fundamental difference I think is that the self technique uses closures and the bind uses method encapsulation… so in theory the self is more performent…

    @kow: I am not sure I understand what you mean? Maybe you can give an example to clarify? If I understand correctly binding to this wouldn’t be usefull outside of the “first level” either?

  7. MarkD

    Isn’t this closure solution (‘.self’ ) considered bad practice because of possible memory leaks escpecially in our good old friend ie6? Closures can be very powerful but they are quit tricky to handle.
    For example you have to clean up the references yourself onBeforeUnload to prevent leaks?
    Moo takes care of that when you use their method.

  8. chris

    thanks been punching myself dealing with the pitfalls of bind and found this how to, thanks, self rocks@!

  9. Have written dozens of classes over the last few years and today I was spinning my wheels while creating a new element and trying to access this as a reference to the element as well as bind(this) to access class methods and options….

    Thanks David for posting this have not used the self method in awhile and it was exactly what I was looking for!!!

    var self = this; // .bind(this) on event functions obviously will not work!
    new Element('li', {
    	html: this.markQuerySelection(r.title),
    	rel: this.liFocus+i,
    	styles: Object.merge({
    		'background-color': (i%2?this.options.listEvenColor:this.options.listOddColor)
    	}, this.options.listItemStyles),
    	events: {
    		mouseover:function(e){
    			this.tween('background-color', '#fffcb0')
    		},
    		mouseout: function(e) {
    			this.tween('background-color', (i%2?self.options.listEvenColor:self.options.listOddColor))
    		}
    	}
    })
  10. OK. Any ideas on this one? This is a snippet from a JS Class. self.fnUpdateMediaValues(); is another method in the same class.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!