Get friendly with the Natives

Written by Ryan Florence on 24 March 2010 – Posted under all, tipsComments

Have you extended a Native lately? It's an incredibly helpful thing. Often people write ugly functions that take a string or whatever as an argument and return some manipulation of the string. Extending natives is a great way to do the same thing, but it is much prettier (aka: explicit, readable, easier-to-debug.)

The Difference:

I've seen stuff like this:

fn1(fn2(10, fn3('house')));

Hard to figure out what's happening. Instead you can write code like:

fn3('house').fn2(10).fn1();

A Useful, Real Example, zeroPad

I've used this in a couple scripts, it takes a number and returns a string with zeros padded in front: 123 becomes '000123'. Really handy for filenames and the like. Here's the ugly version:

Functionally Based Example

function zeroPad(num, zeros){
  zeros = zeros || 3;
  var str = '' + num;
  zeros.times(function(){ str = '0'+str; });
  return str;
};

// usage
doSomething(zeroPad(document.getElementById('myInput').value, 3));

Native Extentions Based Example

Number.implement({
  zeroPad: function(zeros){
    var str = '' + this;
    zeros.times(function(){ str = '0'+str; });
    return str;
  }
});

// so that it works on both numbers and strings
String.implement({
  zeroPad: function(zeros){
      return this.toInt().zeroPad(zeros);
  }
});

// usage
$('myInput').get('value').zeroPad(3).doSomething();

Side by Side:

doSomething(zeroPad(document.getElementById('myInput').value, 3));
// vs
$('myInput').get('value').zeroPad(3).doSomething();

Awesome? Yes. You can do the same thing to:

Some say extending natives is a bad idea. Personally, I think it's awesome--but this topic is a sore spot for some. Extending natives is a feature of javascript itself that any general application framework like MooTools is entitled to use. There could be an entire article dedicated to this topic but this article isn't it. This article is simply here to show how to use this handy feature.

Flippin' Sweet Array methods

Arian Stolwijk created this amazing gem: Array.Math. Code samples often tell the story faster:

[2,5,1,6].sum(); // 14
[2,5,6,2].product(3); // [6,15,18,6]
[9,12,15].quotient(3) // [3,4,5]

This is all made possible by extending the Array native, see?

Array.implement({

        sum: function(start,length){
            var sum = 0, 
                start = start ? start : 0,
                length = length ? length : this.count()-start;
            length = start ? length + 2 : length;
            for(var i=start;i<length;i++) sum += this[i];
            return sum;
        },

        product: function(p){
            var arr = $type(p) == 'array';
            return this.map(function(entity,i){
                return arr ? (entity * p[i]) : (entity * p);
            });
        },

        quotient: function(q){
            var arr = $type(q) == 'array';
            return this.map(function(entity,i){
                return arr ? (entity / q[i]) : (entity / q);
            });
        },

        // and a whole lot more awesome ...

    });

Quick Tips

  • this is the number or string, or whatever, when inside the method.
  • Return something that makes sense (usually this).
  • You can implement several methods all in the same code block.

This is just one more great tool to help keep your code organized and readable.


A Better Way to use Elements

Written by Sean McArthur on 19 March 2010 – Posted under allComments

Javascript development in the browser is all about the Elements. Manipulating the DOM happens every few lines of code. It’s important enough that some libraries provide little more than DOM enhancements. Not to worry though, MooTools provides greatly in this area as well.

$ and $$

Most of you probably know the two document methods getElementById and querySelectorAll; because if you do, you understand how we select elements with MooTools methods. For those of you that don’t, you provide an ID string of an element in to getElementById, and a CSS selector string to querySelectorAll. The functions $ (which is an alias to document.id, see this post on Dollar Safe Mode for details) and $$ are basically equivalent to getElementById and querySelectorAll, respectively. Of course, since it’s MooTools, they’re more than that.

The dollar function, if given a string, will basically call getElementById on the document. If passed an element, it will just return the element, and if you pass an object with a toElement method, it will try to convert it to an element (we’ll explore that more a couple sections down). A key difference you’ll find between MooTools’ dollar function and jQuery’s is this: MooTools’ $() will only ever return 1 Element, and it will return null if no matching element is found. This means unless you’re absolutely 110% certain the element will exist, you’ll need to check the returned value before starting to call Element methods on it.

var loginEl = $('Login');
    if (loginEl) {
            loginEl.fade('in');
    }

The MooTools Team prefers two separate methods for the selecting elements; to remove any doubt about what a certain function call may be returning, we have one method for individual elements and another for multiple elements. In this case, it’s preferable to be explicit, instead of relying to ambiguous auto-magic. When we see $, we expect an element if it exists. When we see $$, we expect an array of elements (which, as you know, an array can always be empty). The double dollar function has some neat tricks that are explained in its own section below.

All this talk about Elements, but only about how to select them. MooTools also provides an excellent Element construction API.

new Element()

With vanilla JS (mmm, vanilla…), you’d use document.createElement whenever you wanted to create and add a new element to the DOM. MooTools tries to make the JavaScript API more pleasant to use; part of that is a more consistent and easy to use syntax and part of it is using more Object-Oriented programming practices. It feels a lot more OO when creating objects using the new keyword, whereas the standard way is more procedural.

It turns out that every element you could create inherits from the Element prototype. Specifically, the elements you create through document.createElement would be HTMLDivElement, or HTMLParagraphElement, or whichever element you create. Like I said, they all inherit from the base Element prototype, and then HTMLElement, and so on. MooTools extends the base Element class, so that all elements receive some MooTools love.

MooTools augments the Element native, providing a super-duper sweet constructor. You can provide the tag name, and then an object of properties to set on the new element. The returned object is of the same type as the $ method mentioned above. The properties you can set are fairly extensive, so check out the documentation to learn more about them, but here’s a demonstration.

toElement

The dollar method provides another function: converting the instance of class into an element(-al?) form. This is similar to a toString function, which converts objects into strings when needed. You can define a method in a class called toElement, and return an element to “represent” the instance. Let’s take a look at a snippet from a Person Class:

Several extensions in MooTools More take advantage of this, like Form.Request, Form.Validator, HtmlTable, and others. And many plugins in the Forge use this approach as well. This means that after creating an instance of one of these classes, you can just hold on to the instance in your code. Whenever you want to affect the element that the instance is controlling, you just use $(instance) to retrieve it.

Aaron even cooked up a ToElement mixin, and wrote a bit more about this over here.

Elements

I pointed out earlier that $$ returns an array-like object containing Elements. It actually returns an object called exactly that: Elements. Behind the scenes, MooTools gets an array of all the elements that meet the selector (so it's still an array), and then extends the array with all the Elements methods. Why would we want that?

All the methods that MooTools adds to the Element native are added to the Elements class as well. You can do some pretty nifty chaining because of this. First of all, you don’t have to check that it didn’t return null. This is because any method you call on Elements, will loop through the array and try to call the method on each individual element. Even with an empty array, the loop won’t cause an error. And any method you call that would normally return a value, will return an array of the values from each element. An example should make this clearer:

//assigns a click event to all A tags
    $$('a').addEvent('click',  function(e) {
            e.preventDefault();
            alert(this.href);
    });  

    //gets all divs with an id set, and then returns
    //an array of the IDs  sorted alphabetically
    var ids = $$('div[id]').get('id').sort();  

    //gets all divs with a UL immediately inside
    //and assigns a class name to  the divs
    $$('div > ul').getParent().addClass('has-list');

While you could put together long chains acting on all the elements you’ve selected, I’d advise against this. It certainly looks cool, and will work fine one or 2 methods out on the chain. But every method call will cause another loop through all the elements. If you’re doing a lot of things to every element, you might as well do it all in a single pass. I’ll show you what I mean.

//this would loop through each time at addEvent, addClass, and fade
    $$('li  a').addEvent('click', function(e) {}).addClass('alertable').fade('in');  

    //whereas this will only cause 1 loop
    $$('li a').each(function(link)  {
            link.addEvent('click', function(e) {
                     alert(this.title);
            });
            link.addClass('alertable');
            link.fade('in');
    });

Still, when doing something simple, you can skip the each call, since Elements will handle that for you.

Concluding

MooTools provides a lot of expressive power when working with the DOM. It's consistent API makes it a snap to add events, change styles, create elements and more. The object oriented nature of its implementation makes it so that you can extend Elements for your own purposes. Look forward to my next post where I'll talk about extending Elements in various ways and cover best practices for when you decide to bend Elements to your own will.

Sean McArthur is a software developer at Blazonco.com who is madly in love with MooTools. Most of his contributions involve sharing tips and information about MooTools (and programming in general) at his blog and on Twitter.