12 Steps to MooTools Mastery
This tutorial is about understanding and mastering the MooTools library. It does so by offering a high level introduction to the history and foundations of the Core library: where to start, where to explore, what to master, and more.
Tutorial Details
- Program: MooTools
- Version: 1.2.*
- Difficulty: Intermediate
- Estimated Completion Time: 1 hour
1: Prototypal Inheritance
The foundation of the MooTools framework is really in the prototypal inheritance model of JavaScript. In classical languages, like C++ or Java, a class represents something like a data type or what Jeff Mott called a “blueprint.” These blueprints are then used in the creation of objects. In fact, in these languages nothing is actually created until the “new” operator explicitly invokes them.
With JavaScript however, everything is created immediately, even before you instantiate the objects with the “new” operator. As a prototypal language, this effectively means no blueprints, no “classes”. Instead, we go about using some objects as fully operational bases for other objects. As Douglas Crawford said, in precisely this way JavaScript becomes “more capable and offers more expressive power.” Let’s take a look:
function Nerd(iq) {
this.iq = iq;
this.glasses = true;
this.pants = 'high';
}
function SuperPowers() {
this.strongerThanLocomotive = true;
this.fasterThanBullet = true;
this.canLeapBuildings = true;
}
Nerd.prototype = new SuperPowers();
Nerd.prototype.willWinGirl = function (hotness) {
if(this.iq > (hotness * 20) || this.strongerThanLocomotive){
console.log('maybe');
}
else {
console.log('nope');
}
}
new Nerd(140).willWinGirl(10); // logs "maybe"
The example above is actually a rather popular means of introducing the concept of prototyping. However, if you’re finding this a little too abstract, perhaps a better way to approach this would be to look at prototyping a native JavaScript constructor like String, Array, etc. For example:
Array.prototype.eachhhh = function (fn) {
for (var i = 0, l = this.length; i < l; i++) fn(this[i]);
}
[0,1,2,3].eachhhh(function(item){
console.log(item); // logs: 0,1,2,3
});
Prototyping simple code patterns like the for loop above can save tons of time when working on larger projects. When using the MooTools framework, it’s important to begin thinking of every constructor as being extendable; this is going to save you time down the line and make your code much more flexible. Furthermore, it’s precisely this method of inheritance that is at the core of MooTools, and harnessing this frameworks power means making use of prototyping. Of course, what MooTools does is make this process a whole lot easier for you to access and take advantage of, but we will get into exactly how it does this later on in the article.
2: Object Literal Notation
Wayyyy back in 2006, Chris Heilman was already getting fanatical about the object literal syntax… talking about sliced bread and other craziness. At any rate, for that very reason I’m not going to dwell on this subject too much, instead I’ll assume that you’ve come across this syntax at some point or atleast can grasp it by the simple example below.
//this is not object literal notation
var variable1 = null;
var variable2 = false;
function1(){
// some code
}
function2(){
// some code
}
// the above becomes object literal notation below...
var SomeVariableName = {
variable1: null,
variable2: false,
init:function(){
},
function1:function(){
// some code
},
function2:function(){
// some code
}
}
Like most programming languages, in JavaScript there exist a large number of stylistic preferences and “best practices.” When working with MooTools you’ll find there to be no shortage of these, including: not chaining excessively, capitalizing your class names, comma separating variable declarations, etc…. However, among these, object literal notation is perhaps most fundamental to understanding not only the way in which the MooTools framework itself is structured, but actually how to take advantage of this framework in developing your own code. We’ll develop this idea further throughout the rest of this article and as you’ll see, all the examples from this point forward will be taking advantage of this syntax.
3: The Class Constructor
If JavaScript doesn’t have “classes,” then why is there all this hype around Motools and classes? In May of last year, Aaron Newton published an excellent comparative piece on jQuery and MooTools. Among other things, he addressed precisely this question of classes in a very succinct way: “Despite its name, the MooTools Class function is not really a class nor does it create them. It has design patterns that might remind you of classes in a more traditional programming language, but really Class is all about objects and prototypal inheritance.”
As Aaron goes on to detail, the MooTools framework is pushing for powerful and ultimately simple ways to organize and structure your code, ways which are elegant but also familiar, and not just semantically, but in their capacity to behave in classical design patterns. In fact, you’ll find utilizing “classes” in your code base opens up your code to many powerful programming patterns: the mediator, the mixin, etc…
A simple MooTools class will look something like this (notice the syntax):
var YourClass = new Class({
variable1: false,
initialize: function(){
this.toggleVariable();
},
toggleVariable: function(){
this.variable1 = !variable1;
}
});
var yourClassInstance = new YourClass();
yourClassInstance.toggleVariable(); // this.variable1 == false
Not too complicated, right? Once you begin structuring your code in classes like these, you’ll find that your code repository will become not only a lot more organized and manageable, but actually smaller!
4: Class.Mutators
So how exactly does it become smaller? Returning to JavaScript’s prototypal inheritance model and how it relates to the Class constructor, MooTools provides us with Extends and Implements. As properties, both are fundamental to the production of your MooTools subclasses and make this whole protyping mess a bit more intuitive. At a high level, Extends gives your subclass access to all the methods of it’s base class, where methods and properties of the same name are overwritten (not to worry, they’re still accessible through the parent() method). Similar to Extends, Implements adopts properties from one or more other classes, but without the inheritance model.
Consider briefly Digitarald’s fancy upload plugin for Mootools. In this program Harald defines several classes, one of which is called the ‘File’ class. File houses the core functionality that a file object needs to interface with his uploading program and for this very reason is perfect for being extended; one might create an “Image File” subclass, a “Text File” subclass, etc. By modeling your code in this way, you are able to build your code up, rather than out. Consider the example below for how to use Extends:
var YourSubClass = new Class({
Extends: YourClass, //here we are extending "YourClass" from our previous example
variable2: false,
initialize: function(){
this.parent(); // this will call the initialize function from the bass Class "YourClass"
},
//here we are overwriting the toggle Variable function of "YourClass" with a new function
toggleVariable: function(){
this.variable1 = !variable1; // notice variable1 from "YourClass" is still accessible in YourSubClass
this.variable2 = !this.variable1;
}
});
5: Custom Events and Options
The most common usecase I find with Implements is including either the Events constructor or the Options constructor in my classes. As the name suggests, implementing Events allows for both the attachment and firing of custom events on your object, like onComplete, onFailure, onSuccess, onAnything. This level of abstraction becomes particularly useful when you begin sharing your code across several projects, where events behave as mediators between your current project and your plugins. In this way you can finally get away from those nasty one-to-one, bound relationships in your plugins. For example:
var YourSubClass = new Class({
Implements: Events, //here we tell MooTools to implement Events in our sub class (this wont effect the bass "YourClass")
Extends: YourClass,
variable2: false,
initialize: function(){
this.parent();
},
toggleVariable: function(){
this.variable1 = !variable1;
this.variable2 = !this.variable1;
//afterToggle() -- calling "afterToggle" would have made this function a necessary include of YourSubClass
this.fireEvent('toggled'); //instead a custom event is fired called "toggled"
}
});
var yourSubClassInstance = new YourSubClass();
var afterToggle = function(){
alert('i\'ve just been toggled!');
};
//here we add a listener for the custom event, just like we would any other event
yourSubClassInstance.addEvent('toggled', afterToggle);
Besides Events, often you will want to Implement MooTools’ Options. This utility class allows you to automate the setting of a list of optional properties to be set on an instance of your class. Again, this can be very helpful when writing plugins for various projects, allowing for the circumstantial customization of certain properties of your object. Consider the example below:
var YourSubClass = new Class({
//One of the many cool things about the implements property is that it excepts an array.
Implements: [Events,Options], //Here we include Options
Extends: YourClass,
//options are set if the invoker does not explicitly specify a value.
options: {
variable2: false
},
initialize: function(options){
this.setOptions(options); //sets the options
this.parent();
},
toggleVariable: function(){
this.variable1 = !variable1;
this.options.variable2 = !this.variable1;
this.fireEvent('toggled');
}
});
// this will start the class with variable2 = true.
var yourSubClassInstance = new YourSubClass({
variable2: true
});
6: Binding
As your programs become more complex, a proper understanding of scope becomes invaluable. Scope is the way variables in JavaScript relate to any single point of execution — there are global variables, which are variables that can be referenced from anywhere in the document and occupy the lowest executing level, local variables, which are variables limited to their immediate containing functions or closures, and finally, self references, the “this” keyword, which are JavaScript’s way of referencing the context of the current point of execution.
var global = true; //global variable;
var aFunction = function(){
var local = true; //local variable
}
$('button').addEvent('click', function(){
this.addClass('clicked'); // self reference
});
When referencing a variable in your code, JavaScript bubbles from it’s current executing position through all accessible levels of variables until it locates the first and nearest occurrence of a positive match. This behavior is often less than desirable, particularly when dealing with events inside of object literals as they house their own self references. Often developers rely on what are called “lexical closures” to circumvent problems like these, storing the self reference in a variable of a different name. However, MooTools provides an alternative means of achieving this through their bind() method, which is not only cleaner, but a lot more elegant. Consider the example below:
...
addEvents: function(){
$('button').addEvent('click', function(){
//binding substitutes the current self reference for that of the object passed in
this.toggleVariable();
}.bind(this)); // here we bind this to the click event handler
},
toggleVariable: function(){
//code
},
...
7: The Element Constructor
In the example above we targeted an already existing element in the DOM and added an event listener to it. However, it’s not uncommon today that you will see entire web apps load their content dynamically using JavaScript. With the evolution of JSON, being able to generate markup on the fly has become increasing necessary. Enter the MooTools Element constructor. The novel thing about this constructor is that it maintains it’s readability despite it’s large capacity for optional properties (Again, thanks to the object literal notation!). Element accepts an events object, a styles object, plus any individual properties like class, id, src, href, title, etc. That said, it’s also loaded with a ton of methods, the complete list of which is available from the MooTools docs here. Below is a simple example of how to get started:
var el = new Element('div', {
id: 'button',
'html': 'hellloooo',
styles: {
display: 'block',
position: 'relative',
float: 'left
},
events: {
click: function(){
//your code
}
}
});
8: DOM Manipulation
Now that you have your dynamic element, wouldn’t it be great to insert it into the DOM? MooTools provides a really handy list of methods for just that, including:
- inject – places one element relative to the calling element : ‘before’, ‘after’, ‘top’, ‘bottom’
- grab – like inject but in reverse
- adopt – works like grab accept it can accept an array of elements and you can’t specify an exact relation
- wraps – Works like grab, but instead of moving the grabbed element from its place, this method moves this Element around its target
Of these methods, I’ve found adopt’s ability to accept an array of elements absolutely indispensable, especially when structuring larger quantities of dynamic markup. Consider the example below:
var el = new Element('div', {
id: 'button',
styles: {
display: 'block',
position: 'relative',
float: 'left
},
events: {
click: function(){
//your code
}
}
}).adopt(
this.createSpan(), // returns an element which can later be overwritten by a subclass
new Element('a', {
href: 'http://somewebsite.com'
}).adopt(
new Element('strong', {
'html': 'world'
})
)
).inject($(document.body),'top');
The example above makes for a truly object oriented approach to DOM manipulation. When you become a super MooTools ninja, jedi, junky, nerd, you can use the method above to begin abstracting out functions which return elements or arrays of elements, making it possible for your subclasses to target specific methods in modifying your display. Awesome.
9: Request.JSON & Request.JSONP
JavaScript Object Notation or JSON is the lightweight data-interchange format that everyone loves (especially after working with XML). The great thing about JSON of course is that it’s structure is recognized natively by JavaScript, and with many large sites opening up their data to the public via APIs, there’s really no reason why you shouldn’t invest the time to get familiar with it. No longer a cross browser nightmare, whether you’re pushing data to a back-end service or requesting another batch of tweets from twitter, the MooTools Request constructor makes JSON and JSONP incredibly simple. It works with several event listeners and recently a timeout, which is completely neccessary once you start getting into JSONP. (Which you should! It’s so fun.) Here’s a simple example:
var JSONRequest = new Request.JSON({
url: "http://yoursite.com/tellMeSomething.php",
onFailure: function(){
alert('oh nooo!');
},
onSuccess: function(response){
alert('hooray!: ' + response.result);
}
});
10: Fx
At a high level, the Fx constructor allows you to modify any CSS property of an HTML element, which itself accepts a single element and a series of optional properties (duration, transition type, etc.) to create smooth animation effects of colors, slides, scrolls, etc. What’s more, the Fx constructor is fully compatible with Robert Penner’s Easing equations, which are a great way to add a touch of uniqueness to your transitions like bounce, elastic, sin, etc.
If you’re “hardcore” you can actually achieve all of the animation effects using either Fx.Tween(single css style animation) or Fx.Morph (multiple simultaneous style animations). Of course, beyond these there’s Fx.Slide, Fx.Scroll, Fx.Accordian, etc. Here’s a simple example using Fx.Tween:
var myFx = new Fx.Tween($('button'));
myFx.start('background-color', '#000', '#f00'); //this tweens the background color of the button element.
If you’re dying to get deeper into this topic, check out Consider Open’s fx tutorial for a fairly comprehensive introduction to the constructor.
11: Swiff
Originally appearing in Digitarald’s fancy upload, the Swiff object allows your page’s JavaScript to communicate with Flash. This makes it substantially easier to interact with Flash’s unique functionality like video, sound, file streaming, and clipboard accessing features. More over, Swiff allows you to pass values and manipulate the Flash movie using conventions you’re familiar with from JavaScript and Mootools. Integrating flash in this way is particularly useful as we begin taking steps towards offering HTML5 as a progressive enhancement, where, barring user’s have the flash plugin, Swiff can be used to control audio or video on older browsers. Meanwhile, check out the simple example below:
var flashObject = new Swiff('sounds.swf', {
id: 'mySoundManager',
width: 1,
height: 1,
vars: {
myVariable: true, //pass variables into flash on load
},
callBacks: {
//call custom events from your flash object
someEvent: function(){
//code
}
}
});
Swiff.remote(flashObject, 'playMySound') //calls the function "playMySound" from within flash
12: Mootools More & Forge
Now with over fifteen members contributing to the official more plugin repository and over one hundred unofficial plugins already on Forge, it’s no surprise that “Community” is what the MooTools team wanted us as developers to take away from 2009. Indeed people have truly embraced this framework, and now with Forge, we have a great place to meet each other and begin sharing ideas. You’ll find David Walsh, Aaron Newton, 3n, and many others actively contributing amazing code and facilitating an environment capable of both inspiration and utility. In the end, the most helpful way to pick up the MooTools framework is by engaging with the developers around you and ultimately understanding what they are working on and how they’re going about it.
Write a Plus Tutorial
Did you know that you can earn up to $600 for writing a PLUS tutorial and/or screencast for us? We’re looking for in depth and well-written tutorials on HTML, CSS, PHP, and JavaScript. If you’re of the ability, please contact Jeffrey at [email protected].
Please note that actual compensation will be dependent upon the quality of the final tutorial and screencast.