Hello, my name is Luke Bunselmeyer. I’m a fun loving Full-Stack engineer who delights in polyglot programming from back-end to front-end, Java to JavaScript, Web services to Web development.

[ Angular ]

I really enjoy using block-style template inheritance in Jade and Handlebars. From my understanding, this pattern was popularized by Django.

AngularJS rocks, but it relies on template inclusion to define layouts. This means the a layout context is spread across several templates. With block-style template inheritance, layouts are defined within a single template. Moreover, multiple layouts can be DRY’ed up with inheritance.

So I set out to build angular-blocks, an AngularJS module, to support template blocks.

An Example…

First, we define some routes and scaffold the Angular app.

webapp.js

function routes($routeProvider, $locationProvider) {
    $routeProvider.when('/articles', {
        templateUrl: '/article/index.html',
        controller: Controllers.ArticleCtrl
    });

    $routeProvider.when('/articles/:id', {
        templateUrl: '/article/view.html',
        controller: Controllers.ArticleCtrl
    });

    $routeProvider.otherwise({
        templateUrl: '/pages/welcome.html',
        controller: Controllers.WelecomeCtrl
    });
}

angular.module('app', ['angular-blocks'])
    .config(['$routeProvider', '$locationProvider', routes])
    .run();

index.html

<html ng-app="app">
	<head>
		...
	</head>
	<body>
		<div ng-view></div>
	</body>
</html>

Note that <body> only contains a ngView directive. We’re not ngInclude-ing any additional templates, such as a header or footer.

Layouts

According to the Django docs,

Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your site and defines blocks that child templates can override.

With this in mind, let’s define a one-column and a two-column layout.

/layouts/one-col.html

<header data-block="header">
    <h1>Awesome Blog</h1>
</header>

<div data-block="content"></div>

<footer data-block="footer">
    <p>
        <small>Copyright 2013 Blah blah blah.</small>
    </p>
</footer>

The one-col.html layout uses the data-block directive to define three blocks (header, content, and footer). Child templates can override, prepend, append, insert-before or insert-after each block by extending /layouts/one-col.html.

Now let’s create a two-column layout by extending /layouts/one-col.html.

/layouts/two-col.html

<div data-extend-template="/layouts/one-col.html">

    <ul data-block-append="header" class="breadcrumbs">
        <li ng-repeat="crumb in breadcrumbs">
            <a ng-href="{{crumb.url}}">{{crumb.display}}</a>
        </li>
    </ul>

    <div data-block="content">
        <div data-block="main-content"></div>
        <div data-block="side-nav"></div>
    </div>
</div>

The two-col.html layout uses the data-extend-template directive to extend /layouts/one-col.html. The data-block overrides the content block and defines two new blocks: main-content and side-nav. Moreover, the data-block-append directive appends content to the header block.

The resulting template looks like…

<div data-extend-template="/layouts/one-col.html">

    <header data-block="header">
        <h1>Awesome Blog</h1>
        <ul data-block-append="header" class="breadcrumbs">
            <li ng-repeat="crumb in breadcrumbs">
                <a ng-href="{{crumb.url}}">{{crumb.display}}</a>
            </li>
        </ul>
    </header>

    <div data-block="content">
        <div data-block="main-content"></div>
        <div data-block="side-nav"></div>
    </div>

    <footer data-block="footer">
        <p>
            <small>Copyright 2013 Blah blah blah.</small>
        </p>
    </footer>
</div>

So enough with layouts. Let’s create some views…

Views

We extend the one-col.html to create a “nice” landing page.

/pages/welcome.html

<div data-extend-template="/layouts/one-col.html">

    <div data-block="content" class="hero">
        <h1>Yeah! A Blog!</h1>
        <a href="/articles">Read my blog</a>
    </div>

</div>

Finally, the two-col.html layout comes in really handy when putting context specific content in the side-nav block and before the footer block.

/article/index.html

<div data-extend-template="/layouts/two-col.html">
    <div data-block="main-content">
        <article>
            <div class="article-header">
                <h2>
                    <a ng-href="/articles/{{article.titleSlug}}">{{article.title}}</a>
                </h2>
            </div>
            <div class="article-content" ng-bind-html-unsafe="article.content"></div>
        </article>
    </div>
    <div data-block="side-nav">
        <h4>Contents</h4>
        <ul>
            <li ng-repeat="article in articles">
                <a ng-href="/articles/{{article.titleSlug}}">{{article.title}}</a>
            </li>
        </ul>
    </div>
</div>

/article/view.html

<div data-extend-template="/layouts/two-col.html">

    <div data-block="main-content">
        <article>
            <div class="article-header">
                <h2>
                    <a ng-href="/articles/{{article.titleSlug}}">{{article.title}}</a>
                </h2>
            </div>
            <div class="article-content" ng-bind-html-unsafe="article.content"></div>
        </article>
    </div>

    <div data-block="side-nav">
        <h4>Tags</h4>
        <ul class="article-tags-nav">
            <li ng-repeat="tag in article.tags">
                <a href="/articles/tags/{{tag | slugify}}" class="article-tag">
                    {{tag}}
                </a>
            </li>
        </ul>
    </div>

    <footer data-block-before="footer">
        <h4>Related articles</h4>
        <ul class="related-articles">
            <li ng-repeat="article in relatedArticles">
                <a ng-href="/articles/{{article.titleSlug}}">{{article.title}}</a>
            </li>
        </ul>
    </footer>
</div>

Details

For usage and spec’s see https://github.com/wmluke/angular-blocks.