Jade templates for Angular directives

Using Jade instead of HTML for AngularJS directives.

I love Jade. It is to HTML what CoffeeScript is to JavaScript - concise, and no more matching closing tags. I have shown how to use Jade for the page that includes angular app in a previous post. This post shows how to use Jade inside individual angular directives, leaving the rest of the page's markup decision up to you.

When writing Angular directives, I usually store the HTML templates in separate files, usually very close to the JavaScript file.

1
2
3
4
5
6
7
angular.module('App', [])
.directive('foo', function () {
return {
templateUrl: 'foo.tpl.html',
// link, controller etc
};
});

the template foo.tpl.html

1
2
3
<div class="foo">
Foo is <strong>very important</strong>.
</div>

When the angular application runs, the compilation step will fine the templateUrl property, make an Ajax request to grab the foo.tpl.html and then will place the returned text into $templateCache object to avoid multiple fetches.

To avoid async fetching and speed things up I compile all JavaScript code and the templates into a single bundle. I use grunt-html2js grunt plugin to compile templates HTML into JavaScript code to be concatenated into the source bundle.

grunt-html2js converts the template HTML markup into JavaScript and then places the contents into the $templateCache directly. The application then runs as before, but there are no Ajax calls to templates, because the cache is already pre-filled.

1
2
3
4
5
6
7
// output of grunt-html2js
angular.module("foo.tpl.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("foo.tpl.html",
"<div class=\"foo\">\n" +
" Foo is <strong>very important</storng>.\n" +
"</div>");
}]);

I usually add the compiled template as a dependency to the directive to make sure the template cache javascript is loaded before the directive makes the request

1
2
3
4
angular.module('App', ['foo.tpl.html'])
.directive('foo', function () {
...
});

Recently I wanted to use Jade templates instead of HTML directives. So I modified grunt-html2js to detect if the template's extension is .jade and render to HTML before compiling to JavaScript. This has been merged as version 0.2.6. Different directives can use different extensions, so you can try this on individual directives.

Example

I changed one of my projects color-pusher to use Jade for some directives leaving the rest as HTML.

// part of colour-lovers.jade template
.col-sm-6
    .input-group
      input#colourLoverPalette.form-control(
        type="text" size="80",
        placeholder="{{placeholder}}",
        ng-model="paletteId")
// colour-lovers.js directive
var app = angular.module('colour-lovers', ['colour-lovers.jade']);
app.directive('colourLovers', function colourLoversDirective() {
  return {
    restrict: 'E',
    templateUrl: 'colour-lovers.jade',
    replace: true,
    controller: ['$scope', '$http', ColourLoversCtrl]
  };
};

The Gruntfile configuration for compiling templates

1
2
3
4
5
6
7
8
9
10
html2js: {
main: {
options: {
base: 'src',
module: 'color-pusher-widget.templates'
},
src: ['src/*.tpl.html', 'src/*.jade'],
dest: 'tmp/<%= pkg.name %>.templates.js'
}
}

This change made my directives' templates smaller and simpler.