Prototype vs jQuery
by Naneau
One of prototype’s often overlooked functions is Element.addMethods(). Especially in these days of comparison between jQuery and Prototype, it’s important. The basic idea behind jQuery is that you can do a CSS selector query, and apply methods (even chaining them) to the result. Like:
1 2 | $('#element').after('I get inserted after #element'); //insert some html after an element |
In prototype, you could get the same result by doing:
1 2 | new Insertion.After('element', 'I get inserted after #element'); //it's slightly longer! oh noez! |
Prototype encapsulates it’s methods in classes. I personally like this way of working, because it keeps things separated and easy to read up on. There are of course people who like jQuery’s approach better because it keeps everything in one place, and that’s fine. They are both solid frameworks. I have read articles on how jQuery would be better than prototype, and vice versa, but in the end they both provide pretty much the same functionality.
Now, back to Element.addMethods(). Prototype allows you to add methods to it’s extended elements. Those are the kind of elements you get from the $() and $$() functions, so even if you’re not sure what they are, you’re probably already using them. You could easily make prototype behave like jQuery by doing:
1 2 3 4 5 6 7 | Element.addMethods({ after: function(element, html) { element = $(element); new Insertion.After(element, html); return element; } }); |
As you can see, the return element; bit ensures that you can easily chain it, so you can do:
1 | $('element').after('abcdefg').after('hijklmnop!'); |
You could use this behavior to create really useful things. Let’s assume that you want a spinner image displayed next to an arbitrary element. For instance, after a user presses a button or link, you want your spinner displayed next to that. Giving feedback to users that something is happening is important, and this may be a clear way. Let’s assume you have a spinner image at ‘http://yoururl/spinner.gif’.
Prototype has a very handy class called Position. With it you can clone the position of an element to another element. Even if the first element wasn’t really positioned in any way. We’re going to use that to make a spinner appear right next to the source element.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | Element.addMethods({ spin: function(element, text) { element = $(element); var img = '<img src="http://yoururl/spinner.gif" class="icon" alt="Hang on..." /> '; //change this to some url that has your spinner image if (!text) { text = ''; } //make sure there's text in string form element.update('<div class="spin">' + img + text + '</div>') //update the element with a div.spin and the img return element; //return the element for chaining }, stopSpin: function(element) { element = $(element); if (element) { //element exists element.innerHTML = ''; //reset it's contents to nothing } }, spinBeside: function (element, text) { element = $(element); //the element next to which we will spin id = (element.id); id = 'spin_' + id; //id for the spinner var html = '<div id="' + id + '"></div>'; //spinner html var body = $$('body')[0]; //body new Insertion.Bottom(body, html); //insert var spinElement = $(id); //the spinner element spinElement.spin(text); //make it spin, see the spin() method above Position.absolutize(spinElement); Position.clone(element, spinElement, { offsetLeft: element.getWidth() + 10, offsetTop: Math.round(element.getHeight() / 2 - spinElement.getHeight() / 2), setWidth: false, setHeight: false }); //position it return element; //return element for chaining }, stopSpinBeside: function(element, id) { element = $(element); //the element next to which there's a spinner id = (element.id); id = 'spin_' + id; //id for the spinner if ($(id)) { //check whether it exists to be sure $(id).remove(); //remove the element from the document } return element; //return element for chaining } }); |
You could use it on any element (as long as it has an id, but it wouldn’t be too hard to write around that), and get a nice little spinner next to it. Nifty, eh? With the addMethods() method you can add as many functions to Element as you wish. Prototype will automagically add them to every element it returns.
Comments
Very interesting techniques. I love Prototype’s absolutize() method. I’d never heard of that one before. I think I’ll be doing a lot of experimenting with both jQuery and Prototype before I decide which one to commit to.
I think you’re going to find that even though they differ in approach, they will enable you to do pretty much the same thing. They both make javascript suck less