Saturday, January 23, 2010

Organize your spaghetti javascript/java with Google Closure Templates


If you ever developer something in javascript that has to have some html, its a real chore, for me anyway. Plain dom manipulation is pretty easy, but what do you do when you need to insert some dom nodes that weren't there before? I think it's pretty common to write something like this:

//jQuery javascript:
 javascript: 
 var someHTML = 'A new paragraph!';
 jQuery('#paragraphContainerDiv').html( someHTML ); 

The code, if you have jQuery of course, should insert the paragraph as a new node in the selected container. When you're a more advanced js developer, you'll probably try to generate the nodes with some js functions and then append them to the containers and so on, which by the way make things a lot more complicated to the person that maintains the code later on. If you are smart you'll probably think about templating. The normal approach would be to write some functions in which you input some template data:

//javascript: 
 var Template = {
 helloThere : function (name){
  return 'Hello there '+name+' !';
 }
 } 
 document.write(Template.helloThere('Piter')); 

When you paste the code into you firebug, you probably should see a "Hello there Piter !
" text. What we have achieved is to unbind the html from the javascript, which is the right way to go, but still when you look at the Template.helloThere() function, its a pretty messy piece of code. Let us add some internationalization features like so:

//javascript: 
var Template = {
 helloThere : function (hello, name){
  return ''+hello+' '+name+' !';
 }
 }
 
 //english
 document.write(Template.helloThere('Hi there','Piter'));
 //polish
 document.write(Template.helloThere('Witaj','Piter'));
 //french
 document.write(Template.helloThere('Bonjour','Piter'));
 /japanese
 document.write(Template.helloThere('Konnichiwa','Piter'));

It's not hard to imagine how this template would look like within a real exapmle that has 20-50 html tags, full I18n support and additional data variables. Even if you would pass the variables as arrays the main problem stands: spaghetti html and js.
Fortunately there is a way to rapidly develop templates and manage the very easily, especially in a team when the js programmer and web developer are two different people. The answer is Google Closure Templates. The pretty recently featured Template engine is used among the most commonly used G applications like Gmail, co as Google says it's well battle-tested :-), and well documented. It not only speeds up development of Javascript/Java but also makes the code a lot easier to maintain and localize. Let's Have a look on what the code above would look like in GCT, but first you need to follow the instructions on Google code Closure site, in a shortcut (for windows/javascript):

  1. You need to install Java Runtime Environment,
  2. Download the closure template compiler (for js)
  3. Unpack the library and put it in some locally hosted folder (you need Apache or some other web server)
  4. Create a simple.soy file and start editing it

//soy example
{namespace Template}

/**
* Simple soy file example
* Here you declare variables via the documentation comment
* @param hello - the hello message
* @param name - name of the greated person
*/
{template .helloThere}
 
  {$hello} {$name} !
 
{/template}

What you want do do is to compile the simple.soy:
java -jar SoyToSrcCompiler.jar --outputPathFormat simple.js simple.soy

If you get some exceptions... deal with them :) They are usually pretty strait forward and easy to understand. If there are no errors, you'll get a simple.js that is the javascript compiled version of your template file. After linking soyutils.js and simple.js to a html file you can post the code in a script section or just into firebug:

document.write(Template.helloThere({hello:'Hi there', name: 'Piter'})); 
 document.write(Template.helloThere({hello:'Witaj', name: 'Piter'})); 
 document.write(Template.helloThere({hello:'Bonjour', name: 'Piter'})); 
 document.write(Template.helloThere({hello:'Konnichiwa',name:'Piter'})); 

The code looks very similar to the simple javascript function but it has a real advantage, you can request a ready template from your web developer and just fill the gaps with variables, what makes developing really fast and easy for everyone. You even can put your translations in another file so your translators can work at the same time too.

Summarizing Closure Templates have every advantage a normal e.g. php based template engine has, like variables, globals, loops, conditional functions and more. Everything is documented at http://code.google.com/intl/pl-PL/closure/templates/docs/overview.html so as my Linux addicted friends would say RTFM and start using Google Closure Templates. Also there is no catch, Google serves it free under the Apache License 2.0 and encourages strongly to use them.

BTW Still hate Bloggers text editor... that is why every post looks different :)

No comments: