HubLの変数の値を、他の変数の呼び出しに使う(evalっぽいハック)
目次
いわゆる、eval的な挙動になります。あまり文章で説明してもピンと来づらいと思いますので、実際の使用例を先にご紹介します。始めに断っておくと、あまり推奨できる方法ではありません。
例えば次のような構造のデータからnameの値を抽出する場合、普通は次のようにforループを回します。
出力結果
- {% set offices = [
- {
- name: '東京オフィス'
- },
- {
- name: '札幌オフィス'
- }
- ] %}
- {%- for item in offices -%}
- {{ item.name }}
- {%- endfor -%}
- 東京オフィス
- 札幌オフィス
ここまでは何も問題ありません。では、forループ内でオフィス名を出力している「item.name」の「name」をハードコードしないで出力したい場合、どうすればよいでしょうか?
目次
基本となるコード
今回は仮に「name」というkeyが、「name_key」という変数に値として格納されているとしましょう。雰囲気的には次のような感じですが、当然次のコードは動きません。
- {% set name_key = 'name' %}
- {% set offices = [
- {
- name: '東京オフィス'
- },
- {
- name: '札幌オフィス'
- }
- ] %}
- {%- for item in offices -%}
- {{ item.name_key }} {# この呼び出し方では当然動かない #}
- {%- endfor -%}
これは次のように書くことで、期待通りの出力を得ることが可能です(変数宣言は同じなので省略します)。
- {%- for item in offices -%}
- {% set call_value = '{{ item.' + name_key + ' }}' %} {# 変数の呼び出しを文字列として組み立てる #}
- {{ call_value }} {# 文字列として組み立てた変数の呼び出しを展開する #}
- {%- endfor -%}
ここまでの解説ではただ単に非現実的で、使いどころのないコードに思えます。この方法が必要になるのは、次のように「プロパティの数が可変なテーブル的構造のデータを、自動でで出力したい」という場合です。
実用例
次のデータを先ほどの方法を使用して、tableタグで出力してみます。
出力結果
- {%- for item in offices -%}
- {% set offices = {
- columns: {
- name: '支店名',
- address: '住所',
- tel: '電話番号'
- },
- contents: [
- {
- name: '東京オフィス',
- address: '東京都千代田区',
- tel: '03-XXXX-XXXX'
- },
- {
- name: '札幌オフィス',
- address: '北海道札幌市',
- tel: '011-XXX-XXXX'
- }
- ]
- } %}
- <table>
- <tr>
- {# 1. 見出しの出力 #}
- {%- for val in offices.columns -%}
- <th> {{ val }} </th>
- {%- endfor -%}
- </tr>
- {# 2. contentsでループを回す #}
- {%- for item in offices.contents -%}
- <tr>
- {# 3. keyを取得するため、1.と同じようにループを回す #}
- {%- for key, val in offices.columns.items() -%}
- {# 4. 取得したkeyを使用して、contentsのデータを取り出す変数呼び出しを文字列として組み立てる #}
- {% set call_value = '{{ item.' + key + ' }}' %}
- {# 5. 4を展開する #}
- <td> {{ call_value }} </td>
- {%- endfor -%}
- </tr>
- {%- endfor -%}
- </table>
- <table>
- <tr>
- <th> 支店名 </th>
- <th> 住所 </th>
- <th> 電話番号 </th>
- </tr>
- <tr>
- <td> 東京オフィス </td>
- <td> 東京都千代田区 </td>
- <td> 03-XXXX-XXXX </td>
- </tr>
- <tr>
- <td> 札幌オフィス </td>
- <td> 北海道札幌市 </td>
- <td> 011-XXX-XXXX </td>
- </tr>
- </table>
一気に複雑になってしまったので、順を追って解説します。
- 見出しの出力
まずはcolumnsに格納されている各valueを見出しとして出力します。columnsはディクショナリですが、普通にループを回すとvalue値が取得できます。
- contentsでループを回す
次に、contentsの要素ごとにループを回します。これ自体は特に特別なコードではありません。
- keyを取得するため、dictループを回す
contents内の各ディクショナリのvalueにアクセスするため、columnsの各キーを取得する必要があります。for文をこのように記述するとディクショナリのkeyにもアクセスできるようになり、これはHubSpot CMSの公式ドキュメントにも紹介されている方法です。
- 取得したkeyを使用して、contentsのデータを取り出す変数呼び出しを文字列として組み立てる
本記事で紹介するメインのコードです。先ほどの「基本形」セクションのコードと本質的に同じです。
- 4を展開する
こちらも本記事で紹介するメインのコードで、「基本形」セクションのコードと本質的に同じです。
この状態であれば、次のようにコンテンツが増えても、HTMLの出力をしている側のコードは一切修正する必要がありませんので、つまりデータと出力を疎結合に保てている証となります。
出力結果
- {% set offices = {
- columns: {
- name: '支店名',
- address: '住所',
- tel: '電話番号',
- staff_num: 'スタッフ数' {# 追加 #}
- },
- contents: [
- {
- name: '東京オフィス',
- address: '東京都千代田区',
- tel: '03-XXXX-XXXX',
- staff_num: '10名' {# 追加 #}
- },
- {
- name: '札幌オフィス',
- address: '北海道札幌市',
- tel: '011-XXX-XXXX',
- staff_num: '3名' {# 追加 #}
- }
- ]
- } %}
- {# 出力の方のコードには一切変更なし #}
- <table>
- <tr>
- <th> 支店名 </th>
- <th> 住所 </th>
- <th> 電話番号 </th>
- <th> スタッフ数 </th>
- </tr>
- <tr>
- <td> 東京オフィス </td>
- <td> 東京都千代田区 </td>
- <td> 03-XXXX-XXXX </td>
- <td> 10名 </td>
- </tr>
- <tr>
- <td> 札幌オフィス </td>
- <td> 北海道札幌市 </td>
- <td> 011-XXX-XXXX </td>
- <td> 3名 </td>
- </tr>
- </table>
この方法が何より真価を発揮するのは、カスタムモジュール内でHubDBテーブルを選択できるようにしている場合です。これについては基本形のHubDB記事にて、実例を紹介しています。
まとめ
以上、変数の値を他の変数の呼び出しに使う方法をご紹介しました。この方法をとることによってデータと出力の疎結合性を高められるため、コード設計としても出来ることがかなり広がると思います。
しかし公式ドキュメントで紹介されている方法ではなく、ハックの域を出ないものですので、使用の際は万が一のことを考え、影響範囲が広くなりすぎないようにすることをオススメします。
執筆者:Admin