What is BabaJS
BabaJS is an open source Javascript template engine/manager.
Read the full and updated documentation at github
The basic concept is: Template + Data = HTML
Here is a simple example:
<!-- user template -->
<div class="user">
<span><%=data.userName%></span>
<%IF data.hasPic %>
<img src="<% return 'http://imgs.mydomain.com/'+ data.userPic; %>" />
<%ELSE%>
<span>Add User Pic</span>
<%ENDIF%>
<span>User Friends:</span>
<% var myUserName = data.userName; %>
<%LOOP for( var i=0; i< data.friends.length; i++ ) %>
<div class="friend">User <%=i%></div>
<% return this.includeTemplate("friend", window.getFriend( data.friends[i] ) ); %>
<%ENDLOOP%>
</div>
<!-- friend template -->
<div class="friend"><%=myUserName%> is friend with <%=data.userName%></div>
Javascript code to generate the HTML:
BabaJS.generateHTML({
templateName:"user",
requires:["friend"],
ready: function(html){
document.getElementById("test").innerHTML = html;
},
{userName:"me",
hasPic: true,
userPic: "me.jpg",
friends:["amir","baba","daniel","mia","yael"]}
);
The template manager will fetch the template and its dependency templates and will call the ready callback when the HTML is ready.
or you can just do something even simpler like so:
var html = BabaJS.generateHTML("<div><%=data.userName%></div>",{userName:"me"});
document.getElementById("test").innerHTML = html;
It is as simple as that. but you can do so much more with BabaJS – so in this case RTFM is worth it.
Why I Developed it?
While developing a social network at Crytek i did a research at the current javascript templating engines out there. While there were some good solutions, like PURE and EJS, non of them were good fit for my requirements, so i started developing something very simple by my own. I decided to make it an open source project since I wanted to share it with the developing community and thought that maybe there are others that may benefit from it and aren’t happy with the existing solutions.
Main Features
- Sub Templating – you can include additional templates from other template as much as you like.
- Dependency Management – BabaJS keep track about dependencies between templates and JS and CSS files to make sure all are loaded when needed.
- Fast – BabaJS compiles the templates in order to achive fast execution.
- Template Stack Variables – BabaJS allows you to define variables in the template tags and access them from anywhere in the template or from included templates.
- Text Based - BabaJS is doing text manipulation and doesn’t work on the DOM elements, thus allowing it to work on Node.JS as well.
- Template Manager – BabaJS is not only a template engine, but also a manager that provides API to add/remove and create dependencies between templates.
How Does it Work
Template Tags
BabaJS is very similar to PHP. Once you open a template tag you can write javascript code inside it. The template engine will compile the template and store it locally in the compiled version to speed things up.
Template Names
BabaJS is more like a template manager rather then just a template engine, it stores the templates locally for future use and it provide method to manage the templates. In order to identify a template BabaJS requires a unique name for each template. There is an option to just provide a template and get the generate HTML without storing the templates locally, but then you are not using the real power of BabaJS, and only using it as a template engine.
Data
Whenever you request from BabaJS to generate a HTML you need to provide a data object that will be used in the template and will be available in the javascript code as data object.
Documentation
First lets examine the template tags to be used in a template. BabaJS template tags start with <% and ends with %>.
Template Tags
Code Tag
Format: <% code %>
The code tag allows you to execute javascript inside the template. if the code returns a value then BabaJS will replace this tag with the return value. If the code is not returning value, then the BabaJS will just remove the tag from the template after executing the javascript.
Examples:
<% var a=1;%>
<% return a; %>
<% return data.userName; %>
<% return this.includeTemplate("temp1"); %>
In the first code tag we created a local variable a and set it to 1. in the second code tag we return the value of “a” which is 1. In the third code tag we return the value of the userName which was passed in the data object. In the last tag we are calling the includeTemplate method in order to insert additional template.
Assign Tag
Format: <%= code %>
The assign tag is just a short cut of the code tag, where you don’t need to write the return keyword.The assign tag is used only to return immediate value and not to declare and execute other code.
Examples
<%=a%>
<%=data.userName%>
<%=this.includeTemplate("temp1"); %>
Like the previous example, the only thing that was change here is that we removed the “return” keyword.
Condition Tag
Format: <%IF expression %>HTML and/or template tags <%ELSE%> HTML and/or template tags <%ENDIF%>
The condition tag allows you evaluate a javascript expression and to include a HTML and or template tags according to the expression value.
Examples:
<%IF data.val == 1 %>
yes
<%ELSE%>
<%IF data.name=="amir" %>
hi amir
<%ENDIF%>
no
<%ENDIF%>
In this example we check the value of val in the data object and if its equal to 1 we output “yes” otherwise we output “hi amir” if the data.name is equal to amir and then we output “no”
Loop Tag
Format: <%LOOP code %> HTML and/or template tags <%ENDLOOP%>
The loop tag allows you to loop a certain HTML several times. The code section is expected to be a loop and there is not need to add the open brackets.
Examples
<%LOOP for( var i=0; i<10; i++) %>
i=<%=i%>
<%ENDLOOP%>
BabaJS Methods
Once you include BabaJS into your project you can access BabaJS using the global variable BabaJS. The following are the public methods you can access:
generateHTML
generateHTML(obj,data)
this method generate HTML using a given template and a data object. The method can executed in two mode: synchronous, where the function return the HTML in the return value, and asynchronous, where the function return the HTML in a callback function. If the synch mode is used, make sure that the template, and sub templates (if there are) is stored locally, and there is no CSS or JS dependencies that are not loaded already.
Params:
- obj- this parameter can be either a String or an object. in case this is a string then it is the template string to be executed, and the method is executed in the synch mode, which mean that the HTML will return in the return value of the function. If obj is an Object then the followings are a valid attributes:
- templateName - String – a unique name of the template
- URLConvertor – Function – a callback function to be used by the template manager to convert the templateName into a URL in case the template is not stored locally.The template manager will attempt to fetch the template from the server using the URL that you will provide. The callback function gets the templateName in the parameter and should return the template URL as a string. This callback function is required if you don’t provide a fetcher. You can also set this callback in the setConfig method to be global callback for all templates. In case you set a callback in the generateHTML and also set a global callback in the setConfig, then the local callabck will be used.
- fetcher – Function – callback function that allows you to control the fetching of templates that are not stored locally by BabaJS. Provide this callback if you want to fetch templates for the template manager when it needs it. The callback gets as the first parameter the template name, and the second parameter is a callback function to be called when the template is ready. the callback parameter gets the template as a string in the first parameter. To indicate that you failed to fetch the template return false to the callback method. You can also set this callback in the setConfig method to be global callback for all templates. In case you set a callback in the generateHTML and also set a global callback in the setConfig, then the local callabck will be used.
- context - Object – set the callback function context. This is optional and if no context is set, the window object will be set as the default context of callbacks. You can also set this object in the setConfig method to be global context for all callbacks. In case you set a context in the generateHTML and also set a global context in the setConfig, then the local context will be used.
- requires - Array or Object – the template manager knows how to handle dependencies. if a template is depended on another template BabaJS will make sure it has it locally. The template manager also support javascript and CSS dependencies, so if a template is depended on a CSS file, the template manager will make sure the CSS is loaded before generating the HTML. The requires attribute could be either an array of template names, or an object with the following attributes:
- templates - Array – array of template names
- js – Array – array of javascript files
- css – Array – array of CSS files
- ready – Function – callback function when the HTML is ready. the callback will get in the first parameter the genrated HTML, and the second parameter is the template name that was requested. If this callback is not provided then the template manager assume that the generateHTML was called in the synch mode and will try to return the HTML in the return value (this will be possible only if everything is already stored locally by the template manager)
- data – Object – the data object that the template manager will pass to the code of the template tags. you can access the data object by using the “data” keyword inside javascript code.
Examples:
//this is a synch use of generateHTML by providing the template as a string.
var html = BabaJS.generateHTML("<%=data.name%>",{name:"amir"});
alert(html); //will output "amir"
/*
since in this example we didn't provide the "ready" callback, the method will be executed in a synch mode and will try to generate and return the HTML in the return value.
this will work only if "temp1" is stored locally and all its dependencies are loaded already.
*/
var html = BabaJS.generateHTML({templateName:"temp1"},{name:"amir"});
/*
in this example we provide a template name and a convertor callback to return a URL of the template. we also provide a "ready" callback to be used when the HTML is ready.
this will force the generateHTML to be used in an asynch mode.
*/
function onHTMLReady(html,templateName){
switch( templateName ){
case "user-page": loadUserPage(html); break;
case "msg-page" : loadMessagePage(html); break;
}
}
function URLConvertor(templateName){
return templateName+".html";
}
BabaJS.generateHTML(
{templateName:"temp1",
URLConvertor:URLConvertor,
ready: onHTMLReady,
},{name:"amir"});
/*
in this example we provided a fetcher method to handle the fetching of the templates by ourselves. this is useful if you already fetched the template or want to fetch several templates in a batch.
we also provided a dependency between "temp1" to "temp2" and "temp3" which wil tell BabaJS to make sure it has these templates locally before generating the HTML.
*/
function fetchTemplate(templateName,cb){
$.ajax( URLConvertor(templateName) , {success:function(data){cb(data);}});
}
BabaJS.generateHTML(
{templateName:"temp1",
fetcher: fetchTemplate,
requires: ["temp2","temp3"],
ready: onHTMLReady,
},{name:"amir"});
/*
in this example we extended the dependencies to add CSS and javascript library for this template. BabaJs will load these files, if they are not already loaded, and make sure they are added to the head tag of the document.
*/
BabaJS.generateHTML(
{templateName:"temp1",
fetcher: fetchTemplate,
requires: {templates:["temp2"],css:["styles/style1.css"],js:["scripts/jquery.js"]},
ready: onHTMLReady,
},{name:"amir"});
includeTemplate
includeTemplate(templateName,data)
This method needs to be called from templates to include sub-templates in the current template. This method only works in a synch mode, so its important that the template is stored locally. To make sure the sub-template is stored locally you can either set it in the requires attribute of the generateHTML method, or set a dependency in the setConfig method.
Params:
- templateName – String – the template name to incldue
- data – Object – the data object.
Return: the method will return the generated HTML.
ensureLocal
ensureLocal(tempArr,jsArr,cssArr,cb)
This method populate the template manager with templates and load any javascript or CSS files that are not loaded yet. Use this method to populate the template manager in initialization or in any step you need to add multiple templates to the template manager
Params:
- tempArr – Array – array of template names. BabaJS will only fetch templates that are not stored locally.
- jsArr – Array – array of javascript files. BabaJS will only load the files if they are not loaded already.
- cssArr – Array – array of CSS files. BabaJS will only load the files if they are not loaded already.
- cb – Function – callback function that will be called once all the files were loaded successfully. In case of an error an exception will be throw.
Examples:
/*
in this example we make sure t1,t2,t3 are loaded along with some javascript and css files that required for this templates. when the template manager load all the files we call the generateHTML in the synch mode since we know that all the resources are stored locally.
*/
BabaJS.ensureLocal(["t1","t2","t3"],["jquery.js","page1.js"],["style1.css"], function(){
var html = BabaJS.generateHTML({templateName:"t1"},{name:"amir"});
});
setConfig
setConfig(cfg)
This method allows you to predefine some settings so you wont need to repeat them whenever you call generateHTML method.
Params:
- cfg- Object – with the following optional attributes:
- URLConvertor - Function – global function to convert a template name to a URL. this method will be called if you don’t provide a URLConvertor in the generateHTML method and the template manager requires to have a URL from a template name.
- fetcher – Function – global callback to fetch templates.
- context – Object – global context for all callback function you provide.
- dep – Object – This allows you to set a dependency hierarchy for templates. the object is a key/value pair where the key=template name and the value=is an object with templates,js,css which are all arrays of dependency files. Before BabaJS will generate an HTML from a template it will check all the dependencies it has in and will make sure all of them are loaded. The dependencies can have two or more dependencies pointing to each other (no endless loop here), so temp1 could have temp2 as a dependency and temp2 can have temp1 as a dependency, BabaJS will fetch temp1 and temp2 whenever you request temp1 or temp2 if they are not stored locally.
Examples:
/*
in this example BabaJS will fetch the "temp1","temp2","temp3" and "js1.js","js2.js" and "style1.css" before generating the HTML.
*/
BabaJS.setConfig({
dep:{
"temp1":{templates:["temp2","temp3"], js:["js1.js","js2.js"]},
"temp2":{templates:["temp1","temp3"],css:["style1.css"]},
"temp3:{templates:["temp1"],js:["js1.js"]}
},
URLConvertor: URLConvertor,
context : this
});
BabaJS.generateHTML({templateName:"temp1",ready:onHTMLReady}, myData );
removeTemplate
removeTemplate(templateName)
This method allows you to remove a template from the template manager, so the next time you will request this template the template manager will try to fetch it.
Params:
- templateName – String – the template to remove.
Known Issues
Version 1.0
- For now BabaJS support only deceleration of variables from type “string” ,”number” and “boolean”. in case you declare an object variable it won’t be available in other code segments. In order to solve that i need to JSON.parse and JSON.stringify the object. Most modern browsers already have a built-in JSON object but i didn’t want to rely on it, and didn’t want to bloat the code with JSON implementation. so for now i don’t support it.
Version 1.0.1 (27/4/2011)
The main change here is that now you can declare any variable inside a code segment as long as you have the JSON object in the window context. FF 3.6 > and Chrome already has it. For old implementation i suggest that you add the JSON.org implementation if you need to declare object variables in the template.
- fixed a bug in _ensureLocal – if the totalCount==0 then we return immidiatly
- add a method addTemplate – allowing developer to add one template at a time
- added a private _log method
- added a private _stringify method – this allows for browsers that have window.JSON to declare objects and array in code tags. For older browsers it is recommended to include a JSON lib to the project.
- fixed a bug in _compile – code tags that didn’t had space between the tag and the code were not parsed correctly. i.e: <%return “a”%>
- fixed a bug in _findVar – i remove code inside of (…) in var declerations. for example, var a=fn(q,w),r=4; produced vars=[a,w,r] so now it produce vars=[a,r]
Download
You can download the entire project from here.
Feedback
If you have an issue or a suggestion for BabaJS feel free to either leave a comment or contact me at harel.amir1 [at] gmail.com








