Kidomi - a JSON-based templating library
Posted on 05 January 2014 in Articles • 3 min read
Certainly, ClojureScript plays a major role in why the templating syntax seems so natural and pleasant, e.g.:
1 2 3 4 5 6 | (node [:span {:style {:color "#aaa" :text-decoration "line-through"}} "hello world!"]) |
But with JavaScript arrays and objects, there is a way to create something similar
1 2 3 4 5 | kidomi(['span', {'style': {'color': '#aaa', 'text-decoration': 'line-through'}}, "hello world!"]) |
Which outputs a HTMLElement with the following nested structure:
1 2 3 | <span style="color:#aaa; text-decoration:line-through"> hello world! </span> |
Kidomi is written in CoffeeScript. It is covered by unit tests via QUnit and can be used by a Google Closure compiler in an ADVANCED_MODE compilation or separately (e.g. to produce a minified output).
Usage
The kidomi(data) function returns a HTMLNode constructed from a data, for example:
1 2 3 4 5 6 7 8 9 10 | elem = kidomi( ['div#main.content', ['span', {'style': {'color': 'blue'}}, 'Select file'], ['form', { 'name': 'inputName', 'action': 'getform.php', 'method': 'get'}, 'Username: ', ['input', {'type': 'text', 'name': 'user'}], ['input', {'type': 'submit', 'value': 'Submit'}]]]) |
The generated HTML element is:
1 2 3 4 5 6 7 8 | <div id="main" class="content"> <span style="color: blue;">Select file</span> <form name="inputName" action="getform.php" method="get"> Username: <input type="text" name="user"></input> <input type="submit" value="Submit"></input> </form> </div> |
Syntax
The general syntax of kidomi is: node = kidomi(parsableObject). Here, node is a HTMLElement or in a more generic case a DOM node.
The parsableObject is:
- A string. The returned object is a Text node.
- A number. It is automatically converted to string and the returned object is a Text node.
- A node. The returned object is the same node.
- An array. This should be discussed a bit thoroughly:
The syntax of the parsableObject array is simple and very flexible. It consists of at least one item, which is:
1 | ['element#id.class1.class2.classN'] |
Here, id - is the id attribute of the node, class1.class2.classN - CSS classes of the node, i.e. class="class1 class2 classN".
For example:
1 2 3 4 5 6 | ['div'] // <div></div> ['div#content'] // <div id="content"></div> ['span#user.username'] // <span id="user" class="username"></span> ['span.password'] // <span class="passwordd"></span> ['div.main.dialog'] // <div class="main dialog"></div> // etc. |
The second item is either an attributes object, or a sub-parsableObject. The attributes object has the following syntax:
1 2 3 4 | {'class': ['class1', 'classN'], 'style': {'prop1': 'val1', 'propN': 'valN'}, 'attribute1': 'value1', 'attributeN': 'valueN'} |
or
1 2 3 4 | {'class': 'class1 classN', 'style': 'prop1:val1; propN:valN;', 'attribute1': 'value1', 'attributeN': 'valueN'} |
The class and style key-value pairs or strings are optional.
- The class key-value pair is an array or a string with CSS classes' names applied to the node. It is appended to the classes found in the first item of the parsableObject array.
- The style key-value pair is an object or a string of CSS style properties of the node.
The attributeX key-value pairs are the attributes of the node.
For example:
1 2 3 4 5 | ['a', {'class': ['biglink'], 'style': {'color': 'red'}, 'href': 'http://github.com'}] // <a href="http://github.com" class="biglink" style="color:red;"></a> |
The rest of the array items are nested parsableObjects or in a special case - an array of arrays with parsableObjects. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Nested elements ['div', ['div', ['span.name', 'Name: '], ['span.lastname', 'Last name: ']]] /* <div> <div> <span class="name">Name: </span> <span class="lastname">Last name: </span> </div> </div> */ // Expandable nested array ['tr', [['td', 'First'], ['td', 'Second'], ['td', 'Third']]] /* <tr> <td>First</td> <td>Second</td> <td>Third</td> </tr> */ |
Building and testing
You will need the following tools to build and test kidomi:
- GNU Make. This is used to run the Makefile script.
- CoffeeScript compiler. This is enough to build the library.
- Google Closure compiler. This is used to build the optimized version of the library. The CoffeeScript code is written with the Closure restrictions in mind.
- PhantomJS is used to run the unit tests from a shell. You can as well run them in a normal browser.
Advanced usage
Referencing elements
One of the patterns where kidomi might be especially handy is when you have to create certain HTML elements before adding them in a DOM structure. For example:
1 2 3 4 5 6 7 8 9 | button = kidomi(['button']); button.onclick = function(){ alert('Hello world'); }; myDiv = kidomi( ['div', ['span', 'Click me:'], button]); document.body.appendChild(myDiv); |
List comprehensions in CoffeeScript
List (array) comprehensions are very handy to use as the expandable array elements, for example:
1 2 3 4 5 | ['tr', [['td', '1'], ['td', '2'], ['td', '3']]] # can be written as: ['tr', (['td', "#{i}"] for i in [1..3])] |