Extending Prototype - a better syntax for DOM insertion
When I first met Prototype, it was love at first sight. However, there is one thing in Prototype which I disliked from the very beginning: its DOM(Document Object Model) insertion syntax. Despite vast syntactic improvements in version 1.5, inserting content is still done like this:
new Insertion.Top('elementId', 'content')
How ugly! How unprototypish!
Luckily, there is something we can do about it.
Following – again – Justin Palmer's excellent tutorial, we can add new methods to the Element object using Element.addMethods(). Element.addMethods() takes one parameter, a hash of methods, with which it extends the Element object and which become available to each DOM element.
Element.addMethods({
insertionBefore: function(element, content) {
new Insertion.Before(element, content);
return $(element.previousSibling);
},
insertionTop: function(element, content) {
new Insertion.Top(element, content);
return $(element.firstChild);
},
insertionBottom: function(element, content) {
new Insertion.Bottom(element, content);
return $(element.lastChild);
},
insertionAfter: function(element, content) {
new Insertion.After(element, content);
return $(element.nextSibling);
}
});
This code snippet adds insertionBefore(), insertionTop(), insertionBottom() and insertionAfter() methods to each DOM element so that you can now write
$('myUl').insertionTop('<li>a new list item</li>')
rather than the old and clumsy
new Insertion.Top('myUl', '<li>a new list item</li>')
Even better, as these added methods return $(element) you can chain them together so this is perfectly possible:
$('myUl').insertionTop('<li>a new list item</li>').addClassName('just_updated')
There is a small demo available and you can download the source code here (as part of my small, upcoming add-on library to Prototype).
Aug. 18, 2006 - Update: After reading Brandon Aaron's post on a similar issue, I modified these insertions method so that they return the inserted node rather than parent element, which makes much more sense.
So this:
$('myUl').insertionTop('<li>a new list item</li>').visualEffect('Highlight')
will highlight the appended node (using one of the famous script.aculo.us effects) rather than the parent element. Thanks Brandon!
The demo and source code have been modified accordingly.
Comments
-
That is a nice addition to these clean up methods. Nice work! I look forward to using these in the near future.
Fri, August 18 at 01:29 AM
-
Yeah, this is because IE does not have a way to automagically extend every dom element by default. Everything is just a simple object in IE. Firefox can just extend the HTMLElement object and Safari has a little hack that allows this to work on all dom elements. So … we have to explicitly call Element.extend or just use $() to insure that the element gets extended.
Tue, August 22 at 01:15 AM
-
You’ve got an extra ’ in your fourth code block.
Tue, August 22 at 01:17 AM
-
BTW … I went ahead and wrote some simple unit tests for these methods. These tests just insure that we do indeed get back the new element.
testInsertionBefore: function() {with(this) { var element = $('testInsertions'); var newElement = element.insertionBefore(''); assertEqual('insertionBefore', newElement.id); }}, testInsertionTop: function() {with(this) { var element = $('testInsertions'); var newElement = element.insertionTop(''); assertEqual('insertionTop', newElement.id); }}, testInsertionBottom: function() {with(this) { var element = $('testInsertions'); var newElement = element.insertionBottom(''); assertEqual('insertionBottom', newElement.id); }}, testInsertionAfter: function() {with(this) { var element = $('testInsertions'); var newElement = element.insertionAfter(''); assertEqual('insertionAfter', newElement.id); }}Fri, August 25 at 16:34 PM
-
Whoops … forgot you’ll need some added HTML as well …
Fri, August 25 at 16:43 PM
-
oh and of course I can’t just post the html like that :)
<div id=”testInsertions”></div>
Fri, August 25 at 16:44 PM
-
I guess not like that either … I tried :/
Fri, August 25 at 16:44 PM
-
Great Prototype extension. This is exactly what I was meaning to get around to writing one day. There’s something so exciting about writing $(‘node’).method(arg) instead of Element.method(‘node’, arg).
Tue, August 29 at 21:39 PM
-
[...] With the flurry of changes recently to prototype I was inspired to change a few of my methods to be a little more inclusive and useful. I originally had a set of methods to help in adding elements created via document.createElement() to the DOM and I was using Tobie’s insertion methods. However, they didn’t really fill the gap. The methods need to be able to take both HTML and an HTMLElement to add to the DOM and they need to return the added element with Element.extend() called on it. So I present Element.append, Element.prepend, Element.after and Element.before. Element.append and Element.prepend will use Insertion.Bottom and Insertion.Top if HTML is passed. The Element.after and Element.before will use Insertion.After and Insertion.Before if HTML is passed. It should be noted that these functions need the latest prototype, 1.5_rc1. [...]
Wed, September 06 at 00:48 AM
-
[...] Bytes & Pieces » Blog Archive » Extending Prototype – a better syntax for DOM insertion When I first met Prototype, it was love at first sight. However, there is one thing in Prototype which I disliked from the very beginning: its DOM insertion syntax. Despite vast syntactic improvements in version 1.5, inserting content is still done like t (tags: prototype extension dom javascript) [...]
Sat, September 09 at 22:15 PM
-
It seems as though the inserted element doesn’t always get returned properly in ie 6. Perhaps I am using it incorrectly?
var table = $('mDiv').insertionAfter('<table border=1></table>'); var row = table.insertionBottom('<tr></tr>'); var cell = row.insertionBottom('<td>cell</td>');Sun, January 07 at 15:35 PM