With the rise of JavaScript MVC frameworks, writing templates has become a large part of many web developer’s workflow. As such, I thought I’d share a tip that has made my templates far more readable and maintainable over the years, ternary operators.
Note: For my examples I’m using Underscore’s templates, but this same tip applies to any templating language, even traditional server side ones like PHP.
Example
Let’s say you have the following data for your application:
var items = [
{ name: 'Clock', selected: false },
{ name: 'Chair', selected: false },
{ name: 'Radio', selected: true }
];
And you want to run this data through a template to generate an HTML list. You might start with something like this:
<ul>
<% _.each( items, function( item ) { %>
<li>
<%- item.name %>
</li>
<% }); %>
</ul>
This works fine. But chances are, for a real application you’ll need to do something significantly more complicated than this. As a first step, let’s say you have to add a CSS hook for selected items. You could accomplish that with an if check around each list item:
<ul>
<% _.each( items, function( item ) { %>
<% if ( item.selected ) { %>
<li class="selected">
<% } else { %>
<li>
<% } %>
<%- item.name %>
</li>
<% }); %>
</ul>
Unfortunately this adds 4 lines of code and some unfortunate indentation just to add a simple class. Another alternative is to put the if check within the attribute:
<ul>
<% _.each( items, function( item ) { %>
<li class="<% if ( item.selected ) { %>selected<% } %>">
<%- item.name %>
</li>
<% }); %>
</ul>
This isn’t bad, but personally I find this code difficult to scan. I prefer to handle this situation with a ternary operator:
<ul>
<% _.each( items, function( item ) { %>
<li class="<%= (item.selected) ? 'selected' : '' %>">
<%- item.name %>
</li>
<% }); %>
</ul>
Yes this is a stylistic thing, but I find this clearer and more readable. This will produce an unnecessary empty class attribute on non-selected items, but I believe the readability of the code to be far more important.
For added fun, ternary operators can be nested. Say your application now has to handle deleted items:
var items = [
{ name: 'Clock', selected: false, deleted: true },
{ name: 'Chair', selected: false, deleted: false },
{ name: 'Radio', selected: true, deleted: false }
];
The following template shows how nested ternaries could be used to handle either a selected or deleted hook:
Note: This assumes that the selected and deleted states will not occur at the same time.
<ul>
<% _.each( items, function( item ) { %>
<li class="<%= (item.selected) ? 'selected' :
(item.deleted) ? 'deleted' : '' %>">
<%- item.name %>
</li>
<% }); %>
</ul>
Here are a couple other examples of how you could structure this check. The most important thing is to find something that works for you, or more importantly, the person who will be maintaining your code.
<ul>
<% _.each( items, function( item ) { %>
<li class="<% if (item.selected) { %>selected<% } %>
<% if (item.deleted) { %>deleted<% } %>">
<%- item.name %>
</li>
<% }); %>
</ul>
<ul>
<% _.each( items, function( item ) { %>
<li class="
<% if (item.selected) { %> selected <% } %>
<% if (item.deleted) { %> deleted <% } %>
">
<%- item.name %>
</li>
<% }); %>
</ul>