jQuery 1.4, MooTools 1.2 Compared

By Ryan Florence, published 2010-02-05

Part of the issue Migrated Articles From Original Site Structure..

Background

I recently read jQuery 1.4 Released: The 15 New Features you Must Know over at Nettuts and thought it would be interesting to compare the features of MooTools 1.2 to the new features in jQuery 1.4, released 18 months later.

I didn’t try hard to sound unbiased in this article. I prefer MooTools and it’s evident in the things I notice about jQuery when viewed through my biased eyes. However, please don’t read this as though I’m trying to convince you to switch from jQuery to Mootools, or that jQuery is inferior, or assume that you browse the web with IE, use Windows, drive a Ford, and drink Pepsi. I’m just sharing my thoughts as a mootools developer (I do use jquery on inherted projects)

Anyway, I’ve included a working code snippet for each feature using jsfiddle, save a few, so that you can goof with the code and see how awesome some of these new features in jQuery are, and how awesome some have always been in MooTools. Some of the embedded shells are acting funny so you may need to click the pencil button to really see what’s going on.

Enjoy!

1. Passing Attributes During Element Construction

jQuery 1.4

jQuery('<div/>', { id: 'foo', css: { fontWeight: 700, color: 'green' }, click: function(){ alert('Foo has been clicked!'); } });

MooTools (all versions)

new Element('div',{ id: 'foo', styles: { 'font-weight': 700, color: 'green' }, events: { 'click': function(){ alert('Foo has been clicked!'); } } });

jQuery is looking a lot more moo-ish here by passing an object in rather than chaining everything.

jQuery Shell

MooTools Shell

2. Everything Until!

HTML

<ul id="fruit"> <li>Apple</li> <li>Banana</li> <li>Grape</li> <li>Strawberry</li> <li>Pear</li> <li>Peach</li> </ul>

jQuery 1.4

jQuery('ul#fruit li:contains(Apple)').nextUntil(':contains(Pear)'); // Selects Banana, Grape, Strawberry

MooTools 1.2 + Element.GetUntil Plugin

$$('ul li:contains(Apple)')[0].getAllNextUntil(':contains(Pear)); // more mooish $('fruit').getElement('li:contains(Apple)').getAllNextUntil(':contains(Pear));

I thought these new until methods were interesting so I extended MooTools with similar functionality. See my post about Element.GetUntil.

jQuery

MooTools

3. Binding Multiple Events

jQuery 1.4

jQuery('#foo').bind({ click: function() { // do something }, mouseover: function() { // do something }, mouseout: function() { // do something } });

MooTools (all versions)

$('foo').addEvents({ click: function(){ // do something }, mouseenter: function(){ // do stuff a bit better than mouseover }, mouseleave: function(){ // do stuff a bit better than mouseout } });

jQuery 1.4 again is looking a lot more like mootools, very nice because now you can store a handful of events in an object and toss them around.

Note: “MooTools features mouseenter and mouseleave because mouseover/mouseout sometimes just don’t not work as expected. Mouseenter only fires once you enter the element and does not fire again if your mouse crosses over children of the element.” moootools.net

jQuery

MooTools

4. Per Property Easing

jQuery 1.4

jQuery('#foo').animate({ left: 500, top: [500, 'easeOutBounce'] }, 2000);

MooTools 1.2 + Fx.Transmorph Plugin

Fx.Transmorph is the same thing, different syntax:

$('foo').transmorph({height: 100, width: 100}, {width: 'bounce:out'});

MooTools 1.2 + Fx.Flux Plugin

Fx.Flux is unique in that it allows you to define ANY of the Fx.Morph instructions rather than just the transition. Yes, you can change the duration, transition, unit, etc.

$('foo').flux({ 'top':[370, { duration: 1500, transition:'bounce:out' }], 'left':[370, { duration: 3000, transition:'cubic:out' }] });

Just Mootools

You’d have to set up multiple Tween / Morph instances. However, this affords you control over every aspect of the tween (including events), not just the easing.

var foo = $('foo'); var fooFx1 = new Fx.Tween(foo,{ transition: 'elastic:out', duration: 2000, onStart: function(){ // do something fun } }); var fooFx2 = new Fx.Morph(foo,{ transition: 'sine:in:out', duration: 500, onComplete: function(){ // do something important } }); fooFx1.start('left',500); fooFx2.start({'top':500, 'border':'10'});

So yeah, a lot of code. I think jQuery implemented something cool here and I certainly hope to see a version of Fx.Flux in the mootools forge. When we all start getting crazy with canvas and svg we’ll want leaner syntax for animation than the mootools code block above this, and more control than just the easing in jQuery. Oh, Fx.Flux, yes, that’s what I’m thinking of.

jQuery

MooTools Fx.Flux

5. Live Events

That’s just another name for event delegation. I’ve got an entire post on event delegation with mootools. Basic concept, instead of adding the same events (or as jquery calls it, binding events) on multiple elements, just add the event to a single parent element and delegate, or relay the event to the children. Then any dynamically added elements (inserted via ajax, or otherwise) will have the event.

jQuery 1.4

jQuery('ul#foo li').live('click', function(){ // do something with this });

MooTools 1.2 + Element.Delegates

$('foo').addEvent('click:relay(li)');

Some very big differences in the two approaches here.

jQuery listens to the entire document for clicks. That feels a little, erm, less-awesome than it should be. That means every single click goes ahead and finds out if it was an li inside of foo that was clicked. MooTools only listens to the element you tell it to.

MooTools is also more clear about what’s going on. You are adding the event to an element that will relay the event to it’s matched children. The identical code in MooTools to the jquery example would be:

document.addEvent('click:relay(ul#foo > li)');

But don’t ever do that if you don’t have to. Srsly d00d. Don’t get me wrong, event delegation is one of my favorite toys, so I’m very excited it’s part of jQuery now, just a bit disappointed I have to listen to the whole document, he’s going to be a busy man.

Note: Jquery kicks MooTools in the pants when it comes to delegating focusin and focusout . The current implementation of MooTools event delegation doesn’t support the focus and blur methods, but MooTools 2.0 will.

jQuery

MooTools

6. Controlling a Functions Context

In other words, what will this be inside a function? Given this:

var app = { config: { clickMessage: 'Hi!' }, clickHandler: function() { alert(this.config.clickMessage); } }; // jQuery jQuery('a').bind('click', app.clickHandler); // won't work, `this` is the clicked `a` // Mootools $$('a').addEvent('click', app.clickHandler); // same thing

When an anchor tag is clicked, we want to alert this.config.clickMessage , or ‘Hi!’. Here are the solutions:

jQuery 1.4

jQuery('a').bind( 'click', jQuery.proxy(app, 'clickHandler') );

MooTools (all versions)

$$('a').addEvent( 'click', app.clickHandler.bind(app) );

This should have been in jQuery a long time ago. I have a hard time imagining writing a well structured javascript app without binding, or proxy-ing (?) as shown in this example. I think the MooTools syntax is easier as you don’t have to split up the object, just bind it. Things get a little confusing too with jQuery when you’ve got nested methods in an object:

var app = { config: { clickMessage: 'Hi!' }, clickHandler: function() { alert(this.config.clickMessage); }, nested: { keyupHandler: function() { alert(this.config.clickMessage); } } }; jQuery('a').bind({ 'click': jQuery.proxy(app, 'clickHandler'), 'keyup': jQuery.proxy(app.nested.keyupHandler, app) // backwards? } // MooTools $$('a').addEvents({ 'click': app.clickHandler.bind(app) 'keyup': app.nested.keyupHandler.bind(app) // coherent });

Seems really strange to swap the arguments around to accommodate a nested method. MooTools is much clearer here, just pass in the function as you would normally, then bind whatever you want.

jQuery

MooTools

7. Delay an animation queue

jQuery

$('#foo') .animate({'width': 250}) .delay(500) .fadeOut() .delay(1000) .fadeIn();

MooTools 1.2 with Chain.Wait

$('foo') .tween('width', 250) .pauseFx(500) .fade('out') .pauseFx(1000) .fade('in');

jQuery

MooTools

8. Check if an element has something

jQuery 1.4

jQuery('div').has('ul');

MooTools 1.2

$('div').hasChild('ul');

9. Unwrap an element

jQuery 1.4

jQuery('p').unwrap();

MooTools 1.2

Nuthin’ baked in, but if you find yourself needing to unwrap elements often you could extend Element to handle it.

// include this with your other classes and javascript Element.implement({ unwrap: function(){ var parent = this.getParent(); parent.getChildren().inject(parent,'before'); parent.dispose(); return this; } }); // now you've got unwrap $('p').unwrap();

Edit: Thanks to Chee Aun in the comments, he pointed out that I missed text nodes in my solution. Indeed. Check out his gist for a better solution. You would instead target an element to remove rather than a child to oust it’s parent.

jQuery

MooTools

10. Remove elements without deleting data

jQuery

foo.detach(); // Remove it from the DOM // ... do stuff foo.appendTo('body'); // Add it back to the DOM

MooTools (all versions)

foo.dispose(); // Remove from the DOM // ... do stuff foo.inject(document.body); // Add it back to the DOM

Again, this was one of those things that surprised me that jquery didn’t have, especially since jQuery’s focus is the DOM. It’s especially helpful when you’ve got some heavy duty dom manipulation going on: pull everything out, manipulate, the browser doesn’t try to redraw, inject it back into the DOM. Only redraws once.

11. Index enhancements

jQuery 1.4

jQuery('li').click(function(){ alert( jQuery(this).index() ); alert( jQuery(this).index('li.other') ); });

MooTools

var els = $$('li'); els.addEvent('click',function(){ alert(els.indexOf(this)); alert($$('li.other').indexOf(this)); }); // more common $$('li').each(function(element, index){ element.addEvent('click',function(){ alert(index); }); });

This is clearly more valuable to the jquery coding style. I’ve never used indexOf in mootools, I’m usually in an each loop.

jQuery

MooTools

12. DOM Manipulation accepts functions as arguments

jQuery 1.4

jQuery('li').html(function(i){ return 'Index of this list item: ' + i; });

This is actually quite interesting, it’s geared a lot more toward the coding style of jQuery than mootools, but after talking to Thomas Aylott about it, we (read: he), came up with this …

MooTools 1.2 with Elements.setEach Plugin

$$('li').setEach('html',function(i){ return 'Index of this list item: ' + i; }); // actually, there's a ton you can do with setEach function replaceFooWithBar(string){ return String(string).replace(/\bfoo\b/g,'bar'); }; // just like jQuery $$('a').setEach('href', function(currentHref, i){ return currentHref + '?foo=bar'; }); // or pass in an array of stuff and it'll do it all // notice how `html` is accessible in the function $$('a').setEach('html',[ "New foo HTML!", function(html){ return html + ' appended moar foo!'; }, replaceFooWithBar, function(html,i){ return html + ' Index is ' + i; } ]); // or set multiple things, in this case, multiple styles $$('a').setEachStyle({ 'color': function(currentColor, i) { i = i.toString(16); return ['#', i, i, i].join(''); }, 'background-color': function(currentColor, i) { i = (15 - i).toString(16); return ['#', i, i, i].join(''); } });

Radical. Hats off to Thomas Aylott for this 30 minute script.

jQuery

MooTools

13. Determine the Type of Object (sort of)

jQuery 1.4

jQuery.isEmptyObject({}); // true jQuery.isEmptyObject({foo:1}); // false jQuery.isPlainObject({}); // true jQuery.isPlainObject(window); // false jQuery.isPlainObject(jQuery()); // false

I’m not entirely sure how helpful this is. Seems like if an object is empty when you iterate over it, nothing happens, is there a reason to check first? Also, why do I care if it’s {} versus new Object() . I’m genuinely curious, not bashing.

MooTools 1.2

Straight from Keetology: Up the Moo Herd V: Evident Utensil

// JavaScript's typeof operator.. typeof "a"; // 'string' typeof 1; // 'number' typeof {}; // 'object' typeof []; // 'object'.. wait, what? typeof /m/; // 'object' in some, 'function' in others.. typeof $('id'); // 'object'.. you're not helping! // $type.. $type("a"); // 'string' $type(1); // 'number' $type({}); // 'object' $type([]); // 'array'.. nice! $type(/m/); // 'regexp'.. perfect! $type($('id')); // 'element'.. now you're just showing off..

I know, different, but when I read the header this is the type of thing I expected.

14. Closest(…) Enhancements

Nothing in mootools like this. It seems really similar parentsUntil .

15. New Events! focusin and focusout

As mentioned earlier, you can’t delegate the focus and blur methods directly; jQuery has created these two custom events to make it possible. Flippin’ awesome. MooTools 1.2 doesn’t have this ability, but MooTools 1.3 (due any day now) will have focus, blur, and every other event known to geek.

The Score

Already in MooTools 1.1 or 1.2

1, 3, 5, 6, 7, 8, 10, 11

Not in MooTools -core or -more

2, 4, 9, 12, 13, 14, 15

Available as a plugin in the MooTools forge

2, 4, 12

jQuery put the smack down

15 (But hey, 1.3 is coming!)

Conclusion

Obviously, the styles of jQuery v. MooTools are very different so these comparisons are always a bit funny since both frameworks approach javascript differently. I think the jQuery users out there are going to love some of these new features, especially the ones that mootools developers have been using for a while now.

JQuery continues to be a one stop shop for the DOM, packing in everything you could ever want to do to an element (1.4 is over 150k now uncompressed) while MooTools keeps making -core leaner and more modular (there’s even a server version with no browser or DOM stuff), and encouraging users to only pull in the classes and plugins they need. Potayto, potahto.

It’s interesting to note that some of jQuery’s stuff is starting to pass objects in as arguments rather than encouraging long chains. It may just become a bunch of your own Object Oriented Tools (YooTools, oh snap!) Seriously, the new jQuery is a winner, it’s exciting to visit websites that are using any of the great libraries out there, advancing the web experience.