The EJS templating engine is one of the more effective ways to render HTML from Node / Express.js. With an HTML syntax and simple tags for including server-side JavaScript, EJS combines the best of both HTML and Node. While other templating engines such as Handlebars.js can also work with HTML, the EJS format is particularly flexible by enabling the full capability of the JavaScript interpreter in the template body.
When developing HTML templates with EJS, it may often be useful to create helper functions that simplify certain operations. Functions such as IIF can help make code more readable by reducing the number of tags for server-side includes:
//IIF function
function iif(cond,value){
if(cond) return value;
return '';
}
//EJS - Traditional Syntax
<div class="<% if(condition){ %>selected<% } %>">Test</div>
//EJS - IIF Syntax
<div class="<%=iif(condition,'selected')%>">Test</div>
Since EJS is evaluated in an isolated interpreter, it can be challenging to bring those functions into the template renderer. The traditional technique is to add the functions to the app.locals namespace provided by Express:
app.locals.iif = function(cond,value){
if(cond) return value;
return '';
}
The app.locals namespace, however, will only work if using the default renderer provided by Express. The default renderer first loads the app.locals namespace in to the EJS template renderer memory before actually generating the HTML. Running the EJS render function manually will not work, as illustrated:
//This will load app.locals into the EJS namespace
res.render('index', { });
//This will NOT load app.locals
ejs.render(ejstxt,{ });
Luckily, Node.js is built to provide the full source code of each module. The EJS behavior can be verified in node_modules\express\lib\application.js, in the app.render function. The app.locals are added to the template renderer through mixin, which is an alias to a function that simply merges two associative arrays.
The question still remains – what is the best way to write functions for EJS templates? While it is possible to store the functions in the global app.locals namespace, using those functions will always require the Express rendering function instead of the native EJS render capability. The most versatile solution is to create a new JavaScript module for just the EJS helper functions, and pass them as a parameter to the renderer:
//ejs_helpers.js
exports = module.exports = {};
exports.iif = function(cond,value){
if(cond) return value;
return '';
}
//Calling the render function
var ejs_helpers = require('./ejs_helpers.js');
ejs.render(ejstxt,{ _ : ejs_helpers });
//Using the function in EJS
<div class="<%=_.iif(condition,'selected')%>">Test</div>
This technique will make sure that the EJS functions work well across all instances of the renderer, and help compartmentalize the functions for segmentation if the size of the helper library increases significantly in the future.
Written by Andrew Palczewski
About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+
jAOqp9OXni4Vx4CRWMKNmKCzNl7zaWQvkRLtfmOETrqfztFyAvZvjKa5e