JavaScriptのテンプレートエンジンHandlebars入門


Handlebarsを使うべきではない言葉なので修正してくださいという同僚がいたので、まとめてみます。
ただのテンプレートエンジンでデータバインディングとかはないんですが、もし使いどころがあればご参考までに。

基本的には、
http://handlebarsjs.com/
に詳しく書いてあるので、そちらを見てください。

# Handlebarsとは
Handlebarsとはいわゆるテンプレートエンジンで、
JavaScriptの値を参照してHTMLを生成できるもの。


# 書き方
テンプレートは

````
<div>{{name}}</div>
<div>{{age}}</div>
````

という書き方をします。
{{XXX}}内のxxxはJavaScriptのプロパティです。
{{XXX}}と書くことにより、JavaScriptの値を参照して、
それをHTMLとして生成します。

````
<div>{{person.name}}</div>
<div>{{person.age}}</div>
````

という書き方もできます。そのときは値を

````js
   person : {
      name: "Satoshi",
       age : 33,
    }
  }
````
みたいに渡してあげることが可能です。

# Handlebarsを試す
まずはjQueryとhandlebarsをインストールします。

````shell-session
$ bower install jquery handlebars
````

ではちょっと試しに書いてみましょう。

````html:test.html
<html>
<head>
<script type="text/javascript" src="./bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./bower_components/handlebars/handlebars.min.js"></script>
  <script type="text/x-handlebars-template" id="template">
    <h1>{{name}}</h1>
    <div>{{age}}</div>
  </script>
  <script>
    window.onload = function() {
        var source = $("#template").html();
        var template = Handlebars.compile(source);
        var values = {
            name : "Satoshi Watanabe",
            age : 33
        };
        var html = template(values);
        console.log(html);
        $("#contents").html(html);
    }
  </script>
</head>
<body id="contents">
</body>
</html>

````

これを行うことにより

````html
<h3>Satoshi Watanabe</h3>
<div>33</div>
````

が表示できます。


# build-inのhelper

Handlebarsにはいくつかhelperが用意されているので、それを紹介します。

## each
eachはイテレータとして、要素を順番に使用できます。

````
<table border="1">
  {{#each momoclo}}
    <tr>
       <td>{{name}}</td>
       <td>{{color}}</td>
     </tr>
   {{/each}}
<table>
````

とした場合、momocloオブジェクトの要素をひとつひとつ参照します。

````js
    var source = $("#template").html();
    var template = Handlebars.compile(source);
    var values = {
        momoclo : [
            {name : "Kanako Momota", color: "red"},
            {name : "Ayaka Sasaki", color: "pink"},
            {name : "Shiori Tamai", color: "yellow"},
            {name : "Momoka Ariyasu", color: "green"},
            {name : "Reni Takagi", color:"purple"},
        ]
    };
    var html = template(values);
    $("#contents").html(html);
````

## if / unless

````
{{#if author}}
    <h1>{{firstName}} {{lastName}}</h1>
{{else}}
    <h1>Unknown Author</h1>
{{/if}}
````

authorがtrueになれば、firstName, lastNameを出力します。
なければ、else以下を実行します。
unlessはifの逆でauthorがfalseになれば、実行します。

````
{{#unless author}}
    <h1>Unknown Author</h1>
{{else}}
    <h1>{{firstName}} {{lastName}}</h1>
{{/unless}}
````


## with

withはJavaScriptのwithと同じです。
テンプレートを

````
    {{#with momoclo}}
       <div>{{Kanako}}</div>
       <div>{{Ayaka}}</div>
       <div>{{Shiori}}</div>
       <div>{{Momoka}}</div>
       <div>{{Reni}}</div>
    {{/with}}
````

JavaScriptを


````js
var values = {
     momoclo : {
        Kanako : "red",
        Ayaka :  "pink",
        Shiori : "yellow",
        Momoka : "green",
        Reni : "purple",
    }
};
var html = template(values);
````

とかくと、出力は以下のようになります。

````html
<body id="contents">
       <div>red</div>
       <div>pink</div>
       <div>yellow</div>
       <div>green</div>
       <div>purple</div>
</body>
````

## lookup

lookupはあるデータをとりだしてそれを別なデータを取り出すのに使うのに使ったりします。
たとえば、

````javascript
var values = {
   momoclo : [
        {firstname : "Kanako", lastname : "Momota"},
        {firstname : "Ayaka", lastname : "Sasaki"},
        {firstname : "Shiori", lastname : "Tamai"},
        {firstname : "Momoka", lastname : "Ariyasu"},
        {firstname : "Reni", lastname : "Takagi"},
  ],
  color : {
        "Kanako" : "red",
        "Ayaka" : "pink",
        "Shiori" : "yellow",
        "Momoka" : "green",
        "Reni" : "purple",
    }
};
````

というデータがあったとして、
momocloのfirstnameからcolorの値が取りたいとき、以下のようにします。

````
    <ul>
      {{#each momoclo}}
        <li>{{lookup ../color firstname}}</li>
      {{/each}}
    </ul>
````

そうすると、以下のような出力が得られます。

````html
<ul>
    <li>red</li>
    <li>pink</li>
    <li>yellow</li>
    <li>green</li>
    <li>purple</li>
</ul>
````


## その他(時間があったときに追記)
* log
* blockHelperMissing
* helperMissing

# 自分でhelperを定義する

helperはHandlebars.registerHelper()を使って自分で定義できます。
例えば、linkを生成する

````javascript
Handlebars.registerHelper('link', function(text, url) {
   return new Handlebars.SafeString(
      "<a href='" + url + "'>" + text + "</a>"
    );
});
````

というものを用意してあげると、
データを

````javascirpt
    var values = {
        momoclo : [
            {name : "Kanako Momota", url: "http://ameblo.jp/momota-sd/"},
            {name : "Ayaka Sasaki", url: "http://ameblo.jp/sasaki-sd/"},
            {name : "Shiori Tamai", url: "http://ameblo.jp/tamai-sd/"},
            {name : "Momoka Ariyasu", url: "http://ameblo.jp/ariyasu-sd/"},
            {name : "Reni Takagi", url:"http://ameblo.jp/takagi-sd/"},
            ]
    };
````

としたときは、以下のように書くことができます。

````
<ul>
    {{#each momoclo}}
        <li>{{link name url}}</li>
    {{/each}}
</ul>
````

そうすると結果は以下のようになります。


````html
<ul>
     <li><a href="http://ameblo.jp/momota-sd/">Kanako Momota</a></li>
     <li><a href="http://ameblo.jp/sasaki-sd/">Ayaka Sasaki</a></li>
     <li><a href="http://ameblo.jp/tamai-sd/">Shiori Tamai</a></li>
     <li><a href="http://ameblo.jp/ariyasu-sd/">Momoka Ariyasu</a></li>
     <li><a href="http://ameblo.jp/takagi-sd/">Reni Takagi</a></li>
</ul>
````

# プリコンパイル

Handlebarsにはプリコンパイルしておくことが可能です。
ページの読み込むときにコンパイルする必要がないので、こちらをやっておくてページの表示が早くなります。

handlebarsのnpmでインストールしておき、使います。

````shell-session
$ npm install handlebars
````

テンプレートファイルを用意します。

```text:test-template.hbs
<div>{{person.name}}</div>
<div>{{person.age}}</div>
<div>{{person.sex}}</div>
````

テンプレートファイルをプリコンパイルします。

````shell-session
$ handlebars test-template.hbs -f test-template.js
````

それをhtmlに記述します。
使うJavaScriptはhandlebars.jsでもhandlebars.runtime.jsでもどちらでも大丈夫です。


````html:test.html
<div id="output">
<script type="text/javascript" src="./bower_components/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./bower_components/handlebars/handlebars.runtime.min.js"></script>
<script type="text/javascript" src="./test-template.js"></script>
<script type="text/javascript">
var html = Handlebars.templates['test-template.hbs']({
   person : {
      name: "Satoshi",
       age : 33,
       sex : 'M'
    }
});
$('#output').html(html);
</script>
````

これにより、以下が出力されます。

````html
<div id="output">
    <div>Satoshi</div>
    <div>33</div>
    <div>M</div>
</div>
````

ここはGruntで自動化できそうですね。
grunt-contrib-handlebarsを使いましょう。

# API
Handlbars.xxx のようなメソッドはいくつかあるので、
http://handlebarsjs.com/reference.html
を参照してください。