Tuesday, June 3, 2008

Javascript Dom Builder

I hate the Dom. So I decided to fix it.

basic usage

1 domBuilder($get('basic'))
2 .div({id: 'div1', style: 'height:50px;border-style:solid;border-width:4px;padding:1px;'})
3 .div({style: 'float: left;' })
4 .span().text('purple, ').end()
5 .a({href: 'http://www.google.com'}).text('google').end()
6 .end()
7 .div({style: 'float: right;' })
8 .span().text('cat').end()
9 .end();

Adding event handlers

1 domBuilder($get('event'))
2 .div()
3 .span().text('some text').end()
4 .input({id:'evt_test', type: 'text'})
5 .on('blur', function() {alert('blur!!');})
6 .on('focus', function() {alert('focus!')})
7 .end();

using custom (not pre-defined) tags

30 domBuilder($get('custom'), ['select', 'optgroup', 'option'])
31 .select({id: 'select_test'})
32 .optgroup({label: 'swedish cars'})
33 .option({value: 'v'}).text('Volvo').end()
34 .option({value: 's'}).text('Saab').end()
35 .option({value: ''}).text('').end()
36 .end()
37 .optgroup({label: 'german cars'})
38 .option({value: 'm'}).text('Mercedes').end()
39 .option({value: 'a'}).text('Audi').end()
40 .end();

Essentially the DomBuilder function takes a dom element and returns an object that lets you add nodes to it easily. The most common html tags are pre-defined. You can also insert an arbitrary tag with the 'add' method: .add('foo', {id: 'foo'}, although the expected usage is to tell dom-builder about the custom tags you want to use and let it create helper methods for you, as in the third example above. One gotcha of the fluent-interface style is that you may be tempted to leave off the end() calls - proper indentation can make the code look correct when it is not. end() is only optional at the end of the method chain - in other words, final end()s are implicit.

One benefit of the fluent interface style is that it is easy to extend. For example, you could add a css() method, some sort of auto-close method or parameter (analagous to <tag />) so that an explicit end() is not required, etc.

dom-builder is built on top of the YUI library, and is inspired slightly by Ruby's xml-builder. It is not an original idea - it has been done before in similar ways and by smarter people. Still, it's always helpful to work something out for yourself, and from an aesthetic point of view I prefer my API decisions over those solutions anyway. Examples, tests, and source are available here.

1 comment:

Arnabc said...

Thanks for writing up this nice little script, chaining is what i liked the most in your code, this definitely makes dom building a nicer experience. But one thing which is bugging me is that, everytime I call the domBuilder method it loops through the autoTags[] array and creates those functions again and again, don't you think creating those functions each time should be avoided....one last thing that is can you please explain a little bit why did you store 'parent_el.document' in the 'document' property of 'that' object, it's not clear to me or may b I am missing something, but if I remove that line, I get an error. anyway thanks again for the effort....