#

Handlebars 式は Handlebars テンプレートの基本単位です。単独で {{mustache}} 内で使用したり、Handlebars ヘルパーに渡したり、ハッシュ引数の値として使用したりできます。

# 基本的な使い方

Handlebars 式は、二重中括弧 {{}} で囲まれたコンテンツです。以下のテンプレートでは、firstname は二重中括弧で囲まれた変数であり、式と呼ばれます。

テンプレート プレイグラウンドで表示
<p>{{firstname}} {{lastname}}</p>

以下の入力オブジェクトがテンプレートに適用された場合

入力 (プレイグラウンドで表示 - SVGアイコン)
{
  firstname: "Yehuda",
  lastname: "Katz",
}

式はコンパイルされて、以下のように出力が生成されます

# パス式

Handlebars 式は、ドットで区切られたパスにすることもできます。

テンプレート (プレイグラウンドで表示 - SVGアイコン)
{{person.firstname}} {{person.lastname}}

この式は、入力オブジェクトの person プロパティを検索し、さらに person オブジェクト内の firstname および lastname プロパティを検索します。

以下の入力オブジェクトをテンプレートに渡します

入力 (プレイグラウンドで表示 - SVGアイコン)
{
  person: {
    firstname: "Yehuda",
    lastname: "Katz",
  },
}

以下のように出力が生成されます

Handlebars は、非推奨の / 構文もサポートしているため、上記のテンプレートを次のように書くことができます

テンプレート
{{person/firstname}} {{person/lastname}}

# コンテキストの変更

#with#each のようなヘルパーを使うと、ネストされたオブジェクトにアクセスできます。パスに ../ セグメントを含めると、Handlebars は親コンテキストに戻ります。

テンプレート (プレイグラウンドへのリンクSVG)
{{#each people}}
    {{../prefix}} {{firstname}} 
{{/each}}

名前はコメントのコンテキスト内で出力されますが、ルートオブジェクトであるメインコンテキストに戻ってプレフィックスを取得できます。

警告

../ が解決される正確な値は、ブロックを呼び出しているヘルパーによって異なります。../ の使用は、コンテキストが変更される場合にのみ必要です。 {{#each}} のようなヘルパーの子は ../ を使用する必要がありますが、{{#if}} のようなヘルパーの子は使用しません。

{{permalink}}
{{#each comments}}
  {{../permalink}}

  {{#if title}}
    {{../permalink}}
  {{/if}}
{{/each}}

この例では、上記のすべてが、異なるブロック内にあっても同じプレフィックス値を参照しています。この動作は Handlebars 4 以降の新機能です。 リリースノート では、以前の動作と移行計画について説明しています。 Handlebars は、`this` 参照を介してヘルパーとデータフィールド間の名前の競合解決も可能です。

# リテラルセグメント

識別子は、以下の文字を除く任意のUnicode文字を使用できます。

*空白* `!` `"` `#` `%` `&` `'` `(` `)` `*` `+` `,` `.` `/` `;` `<` `=` `>` `@` `[` `\` `]` `^` `` `{` `|` `}` `~`

さらに、`true`、`false`、`null`、`undefined` という単語は、パス式の最初の部分でのみ使用できます。

有効な識別子ではないプロパティを参照するには、セグメントリテラル表記 `[` を使用します。パスリテラルに閉じ括弧 `]` を含めることはできませんが、他のすべての文字は使用できます。

`[` のペアの代わりに、JavaScript スタイルの文字列 `"` と `'` も使用できます。

テンプレート (プレイグラウンドへのリンクSVG)
{{!-- wrong: {{array.0.item}} --}}
correct: array.[0].item: {{array.[0].item}}

{{!-- wrong: {{array.[0].item-class}} --}}
correct: array.[0].[item-class]: {{array.[0].[item-class]}}

{{!-- wrong: {{./true}}--}}
correct: ./[true]: {{./[true]}}

# HTML エスケープ

Handlebars では、`{{expression}}` によって返される値は HTML エスケープされます。たとえば、式に `&` が含まれている場合、返される HTML エスケープ出力は `&` として生成されます。 Handlebars に値をエスケープさせたくない場合は、「トリプルスタッシュ」`{{{` を使用します。

以下のテンプレートでは、HTML エスケープ出力と生の出力を生成する方法について説明します。

テンプレート (プレイグラウンドへのリンクSVG)
raw: {{{specialChars}}}
html-escaped: {{specialChars}}

特殊文字をテンプレートに渡します。

入力 (プレイグラウンドへのリンクSVG)
{ specialChars: "& < > \" ' ` =" }

「トリプルスタッシュ」(`{{{`)で囲まれた式は、生の出力を生成します。それ以外の場合、HTML エスケープ出力は以下のように生成されます。

出力 (プレイグラウンドへのリンクSVG)
raw: & < > " ' ` =
html-escaped: &amp; &lt; &gt; &quot; &#x27; &#x60; &#x3D;

# ヘルパー

ヘルパーは、Handlebars 言語自体の一部ではない機能を実装するために使用できます。

ヘルパーは、たとえば文字列のすべての文字を大文字にするために、`Handlebars.registerHelper` を介して実行時に登録できます。

準備スクリプト (プレイグラウンドへのリンクSVG)
Handlebars.registerHelper('loud', function (aString) {
    return aString.toUpperCase()
})

Handlebars ヘルパー呼び出しは、単純な識別子の後に、ゼロ個以上の パラメーター(スペースで区切られています)が続きます。各パラメーターは、「基本的な使い方」で前述したのとまったく同じ方法で評価される Handlebars 式です。

テンプレート
{{firstname}} {{loud lastname}}

この場合、loud はヘルパーの名前で、lastname はヘルパーのパラメーターです。テンプレートは入力の lastname プロパティを大文字にします。

入力
{
  firstname: "Yehuda",
  lastname: "Katz",
}
出力
Yehuda KATZ

# ヘルパーの戻り値のHTMLエスケープを防ぐ

ヘルパーが Handlebars.Safestring のインスタンスを返す場合、ヘルパーが {{{ ではなく {{ で呼び出された場合でも、戻り値はエスケープされません。すべてのパラメーターが Handlebars.escapeExpression を使用して適切にエスケープされていることを確認する必要があります。

準備スクリプト
Handlebars.registerHelper("bold", function(text) {
  var result = "<b>" + Handlebars.escapeExpression(text) + "</b>";
  return new Handlebars.SafeString(result);
});

# 複数のパラメーターを持つヘルパー

2つのパラメーターを持つヘルパーの別の例を見てみましょう。

テンプレート
{{link "See Website" url}}

この場合、Handlebarsはlinkヘルパーに2つのパラメーターを渡します。文字列 See Website と、下記の入力 people オブジェクトからの people.url の値です。

入力
{ url: "https://yehudakatz.com/" }

ヘルパー関数 link は、スクリプトに記述されているように、ハイパーリンクを生成するために使用されます。

準備スクリプト
Handlebars.registerHelper("link", function(text, url) {
      var url = Handlebars.escapeExpression(url),
          text = Handlebars.escapeExpression(text)
          
     return new Handlebars.SafeString("<a href='" + url + "'>" + text +"</a>");
});

入力パラメーターを使用して出力を取得します。

出力
<a href='https://yehudakatz.com/'>See Website</a>

上記の例では、people.text の値に基づいて、動的なテキストで全く同じヘルパーを使用できます。

テンプレート (SVGアイコン)
{{link people.text people.url}}
入力 (SVGアイコン)
{
  people: {
    firstname: "Yehuda",
    lastname: "Katz",
    url: "https://yehudakatz.com/",
    text: "See Website",
  },
}

# リテラル引数

ヘルパー呼び出しでは、パラメータ引数またはハッシュ引数としてリテラル値を渡すこともできます。サポートされているリテラルには、数値、文字列、truefalsenullundefined が含まれます。

テンプレート (SVGアイコン)
{{progress "Search" 10 false}}
{{progress "Upload" 90 true}}
{{progress "Finish" 100 false}}

# ハッシュ引数を持つヘルパー

Handlebarsは、ハッシュ引数などの追加メタデータを、最後のパラメータとしてヘルパーに提供します。

テンプレート (SVGアイコン)
{{link "See Website" href=person.url class="person"}}

このテンプレートでは、最後のパラメータ href=people.url class="people" は、ヘルパーに送信されるハッシュ引数です。

ハッシュ引数のキーはそれぞれ単純な識別子である必要があり、値はHandlebars式です。つまり、値は単純な識別子、パス、または文字列にすることができます。

以下の入力をテンプレートに渡すと、person.url の値は person オブジェクトから取得できます。

入力 (SVGアイコン)
{
  person: {
    firstname: "Yehuda",
    lastname: "Katz",
    url: "https://yehudakatz.com/",
  },
}

以下のヘルパースクリプトに示すように、ハッシュ引数は最後のパラメータ options から取得し、ヘルパー内でさらに処理できます。

準備スクリプト (SVGアイコン)
Handlebars.registerHelper("link", function(text, options) {
    var attributes = [];

    Object.keys(options.hash).forEach(key => {
        var escapedKey = Handlebars.escapeExpression(key);
        var escapedValue = Handlebars.escapeExpression(options.hash[key]);
        attributes.push(escapedKey + '="' + escapedValue + '"');
    })
    var escapedText = Handlebars.escapeExpression(text);
    
    var escapedOutput ="<a " + attributes.join(" ") + ">" + escapedText + "</a>";
    return new Handlebars.SafeString(escapedOutput);
});

上記のヘルパーの出力は以下のように生成されます。

出力 (SVGアイコン)
<a class="person" href="https://yehudakatz.com/">See Website</a>

Handlebarsは、テンプレートのブロックを使用してヘルパーを呼び出すメカニズムも提供しています。ブロックヘルパーは、任意のコンテキストでそのブロックをゼロ回以上呼び出すことができます。

詳細はこちら:ブロックヘルパー

# ヘルパー呼び出しとプロパティ参照のあいまいさの解消

ヘルパーが入力オブジェクトのプロパティと同じ名前で登録されている場合、ヘルパーは入力プロパティよりも優先されます。代わりに、入力プロパティを解決する場合は、その名前の前に ./ または this.(または非推奨の this/)を付けることができます。

テンプレート
helper: {{name}}
data: {{./name}} or {{this/name}} or {{this.name}}
入力 (SVG画像省略)
{ name: "Yehuda" }
準備スクリプト (SVG画像省略)
Handlebars.registerHelper('name', function () {
    return "Nils"
})

# 部分式

Handlebarsは部分式をサポートしています。これにより、1つのmustache内で複数のヘルパーを呼び出し、内部ヘルパー呼び出しの結果を外側のヘルパーに引数として渡すことができます。部分式は括弧で区切られます。

{{outer-helper (inner-helper 'abc') 'def'}}

この場合、`inner-helper` は文字列引数 `'abc'` で呼び出され、`inner-helper` 関数が返すものは何でも `outer-helper` の最初の引数として渡されます(そして `'def'` は `outer-helper` の2番目の引数として渡されます)。

# 空白制御

テンプレートの空白は、mustacheステートメントの両側から、波括弧の横に `~` 文字を追加することで省略できます。適用されると、その側のすべての空白は、その側の最初のHandlebars式または空白以外の文字まで削除されます。

{{#each nav ~}}
  <a href="{{url}}">
    {{~#if test}}
      {{~title}}
    {{~^~}}
      Empty
    {{~/if~}}
  </a>
{{~/each}}

このコンテキストでは

{
  nav: [{ url: "foo", test: true, title: "bar" }, { url: "bar" }];
}

改行とフォーマットの空白のない出力が得られます

<a href="foo">bar</a><a href="bar">Empty</a>

これは、「スタンドアロン」ヘルパー(ブロックヘルパー、コメント、または部分と空白のみ)である行を削除するというデフォルトの動作を拡張したものです。

{{#each nav}}
  <a href="{{url}}">
    {{#if test}}
      {{title}}
    {{^}}
      Empty
    {{/if}}
  </a>
{{~/each}}

は以下のようにレンダリングされます

<a href="foo">
  bar
</a>
<a href="bar">
  Empty
</a>

# Handlebars式のエスケープ

Handlebarsのコンテンツは、インラインエスケープまたはrawブロックヘルパーの2つの方法のいずれかでエスケープできます。インラインエスケープは、mustacheブロックの前に `\` を付けることで作成されます。Rawブロックは `{{{{` mustache波括弧を使用して作成されます。

\{{escaped}}
{{{{raw}}}}
  {{escaped}}
{{{{/raw}}}}

Rawブロックは、他のブロックヘルパーと同じ方法で動作しますが、子コンテンツがリテラル文字列として扱われる点が異なります。

最終更新日: 2023年2月9日 午後7時9分59秒