2014年10月31日金曜日

【JsRender】include文

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はJavaScriptによる画面レンダリングツール「JsRender」について連載しています。

前回までで「if文」と「for文」のご紹介は終わりました。
それだけ分かってればJsRenderはもう十分やっていけるのですが、JsRenderには他にもチョコチョコ機能がありまして、そういうのを使うと開発効率が向上しますので知っておいて損はありません。

今回は外部定義の取り込み機能「include」についてご紹介します。

includeを使わない場合

JsRenderではテンプレート部分を「scriptタグ」で定義するわけですが、一方のscriptタグの中に、別のscriptタグを取り込む機能が「incude」です。

要するに、

  • 一個のscriptタグに全部書くと複雑だったりサイズが大きすぎる。
  • 同一テンプレートを再利用したい。


こういう需要の為に使う機能です。

例を挙げてみましょう。

「メンバーの名前一覧を表出力する」という機能を想定します。
テーブル出力ですので「ヘッダー」と「ボディ」があります。
ただし、特殊な事情として「スクロール対策として10行置きにヘッダーを挿入したい」という
仕様があります。

画面としてはこんな感じ。



それを実現するソースが以下です。

<script id="jsRenderTmpl" type="text/x-jsrender">
★{{:title}}
<table>
{{for members}}

{{if seq % 10 == 0}}
 <tr>
  <td>名前</td>
 </tr>
{{/if}}

<tr>
 <td>・{{:name}}</td>
</tr>

{{/for}}

</table>
</script>

<script>
var data = {
  "title": "名前一覧",
  "members": [
      {"seq":0,"name": "Tacy1号"},
      {"seq":1,"name": "Tacy2号"},
      {"seq":2,"name": "Tacy3号"},
      {"seq":3,"name": "Tacy4号"},
      {"seq":4,"name": "Tacy5号"},
      {"seq":5,"name": "Tacy6号"},
      {"seq":6,"name": "Tacy7号"},
      {"seq":7,"name": "Tacy8号"},
      {"seq":8,"name": "Tacy9号"},
      {"seq":9,"name": "Tacy10号"},
      {"seq":10,"name": "Tacy11号"},
      {"seq":11,"name": "Tacy12号"},
      {"seq":11,"name": "Tacy13号"},
      {"seq":11,"name": "Tacy14号"},
      {"seq":11,"name": "Tacy15号"},
      {"seq":11,"name": "Tacy16号"},
      {"seq":12,"name": "Tacy17号"}
 ]
};

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

if文とfor文とテンプレHTMLが入り乱れてちゃってますよね?

まあ、このサンプルはカラムが「名前」しか無いので何とでもなりますが、
もっとカラムが増えると、段々と可読性が下がってきます。

そこで、includeの出番です。

includeを使う場合

上記のサンプルの可読性を向上させる為にincludeタグを使ってみましょう。
構造としては以下の3分割にしようと思います。


  • ベース部分を担当する親
  • ヘッダー部のテンプレート
  • ボディ部のテンプレート


これでそれぞれの性質、機能毎にscriptタグが切れますので、
「ちょっとヘッダーだけ修正したい」みたいな要望にも対応しやすいです。

その対応バージョンがこちら。

<script id="jsRenderTmpl" type="text/x-jsrender">
★{{:title}}
<table>
{{for members}}
{{if seq % 10 == 0}}
 {{include tmpl="#jsRenderTmpl_head"/}}
{{/if}}
{{include tmpl="#jsRenderTmpl_body"/}}
{{/for}}
</table>
</script>

<script id="jsRenderTmpl_head" type="text/x-jsrender">
 <tr>
  <td>名前</td>
 </tr>
</script>

<script id="jsRenderTmpl_body" type="text/x-jsrender">
 <tr>
  <td>・{{:name}}</td>
 </tr>
</script>

どうです?
ソースの総量は増えてしまいますけど、キチッと分割されているので見易くなったでしょう?

まあ、ちょっとしたことにイチイチincludeしていると逆に面倒なだけですので、
includeを使うかどうかは、実装者の判断ですね。

上手くやれば巨大な画面でも綺麗にコーディング出来るでしょう。

終わりに

次回はテンプレートに送り込むJSONタグが複雑な場合に活躍する機能「prop」についてご紹介します。

2014年10月27日月曜日

【JsRender】for文

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はJavaScriptによる画面レンダリングツール「JsRender」について連載しています。
今回はif文に続きロジックの基本、for文です。

for文ではないもの

まず前置きですが、今までの例で使用してきましたように、
以下のようにJsRenderに配列を流し込みますと、それはループで処理されます。

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{:name}}
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",sex:"male"},
{"name": "綾波レイ",sex:"female"},
{"name": "ゼルエル",sex:"unknown"}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

ただ、これだと本当に何の芸も無いループに過ぎませんからね。
例えばループの中に更にループを持たせたいとか、ループとは別に通信の成功コードを持たせたいとか、ループ単品ではなくてヘッダー情報とセットでJSONを扱うとか、現実的なコード設計を考えますと、配列ではとても対応出来ません。

配列ダイレクトの使用は、まあ単なる動作確認程度の話。
実際の実装時は、仮に配列で十分なシチュエーションであったとしても、全実装をキッチリfor文型に統一して粒度を合わせた方が綺麗な実装になると思います。

for文

では、さっそく本題のfor文に入りましょう。

上のソースに近い状態でfor文構成にしますと、以下のようなサンプルになります。

<script id="jsRenderTmpl" type="text/x-jsrender">
★{{:title}}
{{for members}}
<div>
・{{:name}}
</div>
{{/for}}
</script>

<script>
var data = {
  "title": "for文サンプル一覧",
  "members": [
      {"name": "碇シンジ",sex:"male"},
      {"name": "綾波レイ",sex:"female"},
      {"name": "ゼルエル",sex:"unknown"}
 ]
};

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>


「{{for members}}」「{{/for}}」でfor文になるわけです。

ちなみに、for文と言っても「for(var i=0;i<10;i++)」みたいな終了条件は設定出来ません。
流し込んだ配列を全件出力します。

「for(Map m : List<Map> list)」みたいな意味合いだと言えるでしょう。

if文との組み合わせ~偶数と奇数~

ここが一つの残念なお知らせなのですが、「偶数の行」「奇数の行」でテーブルの行を色分けする時に使うみたいな
for文の中でのその時の行数の読み分けする機能は存在しないのです。

この為、偶数/奇数を判断したい場合などは最初からJSONデータの中分岐に必要な情報を持たせておく必要があるわけです。

この場合、私だったら行数のカウントをJSONに持たせます。
そして、偶数/奇数の判断はJavaScriptの計算で実現します。

<script id="jsRenderTmpl" type="text/x-jsrender">
★{{:title}}
{{for members}}
<div>
・No.{{:no}}:{{:name}}:
{{if no % 2 == 0}}
  偶数行
{{else}}
  奇数行
{{/if}}
</div>
{{/for}}
</script>

<script>
var data = {
  "title": "for文サンプル一覧・if文と組みわせ",
  "members": [
      {no:"0","name": "あああああ"},
      {no:"1","name": "いいいいい"},
      {no:"2","name": "ううううう"},
      {no:"3","name": "えええええ"},
      {no:"4","name": "おおおおお"}
 ]
};

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>


これで偶数行/奇数行の判断が出来ました。
後はスタイルシートの記述等を入れてしまえば色分けも完了です。

if文の説明になってしまいますが、このように「{{if no % 2 == 0}}」みたいな計算判定も出来ます。

こうやって簡易的なロジックも織り交ぜて実現していくのが現実的な実装と言えるでしょう。

終わりに

今回で「if文」と「for文」の使い方が分かりました。
ハッキリ言って、これだけ分かっていれば十分!!

基本的にテンプレートはシンプルに定義して、複雑な設定が必要な場合はAjax通信先のサーバ側など
別の所で頑張るべきですから……。

しかし、JsRenderには他にも便利機能がありますので、
次回以降はそれらについてご紹介していきたいと思います。

2014年10月8日水曜日

【JsRender】if文

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はJavaScriptによる画面レンダリングツール「JsRender」について連載しています。
今回はロジックの基本中の基本、if文です。

if文(文字列一致)

「if」「else if」「else」は言語の基本中の基本かと思いますが、実は意外に不便することがあります。

例えばjspタグ。

「ifがあってもelseが無い」

elseを実現したい場合はif文ではなくて「when」とかを使わなければならないのですが、
それを知らないプログラマーが「ありゃ。elseは無いんだ。ならifだけで頑張ろう」とかってifだけで強引に書こうとしてグダグダのソースになる悲劇が多発しています。(泣)

今回は基本中の基本であるif文をチェックしていきましょう。

まずは基本から。
メンバーの一覧の性別をチェックして、男性か女性かチェックする機能を作ってみます。

それがこちら。

<div id="result"></div>

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{:name}}は
{{if sex == "male"}}
  男性
{{else sex == "female"}}
  女性
{{else}}
  性別不明
{{/if}}
です。
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",sex:"male"},
{"name": "綾波レイ",sex:"female"},
{"name": "ゼルエル",sex:"unknown"}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

この結果として、以下のように表示されます。



つまり、代表的なif-elseの構えで分岐が実現出来るわけですね。
whenとか使わなくて済みます。
分かり易くて助かりますね。

  • {{if sex == "male"}}
  • {{else sex == "female"}}
  • {{else}}
  • {{/if}}


if文(数値一致)

上は「{{if sex == "male"}}」と文字列一致で行いましたが、数字ならどうでしょう?

それもOKです。

普通に「{{if sex == 0}}」とでも書いて下さい。

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{:name}}は
{{if sex == 0}}
  男性
{{else sex == 1}}
  女性
{{else}}
  性別不明
{{/if}}
です。
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",sex: 0},
{"name": "綾波レイ",sex: 1},
{"name": "ゼルエル",sex: 2}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

ちなみに、JavaScriptは型の検証がいい加減ですから、


  • {{if sex == 0}}
  • {{if sex == "0"}}


このようにダブルクォート(")で括ろうと括るまいと同じように処理されます。

if文(数値大小比較)

では、数値の大小比較はどうでしょう?

これも普通に「<」「>」が通用します。

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{:name}}は
{{if 10 <= age && age <20 }}
  10台
{{else 20 <= age && age <30}}
  20台
{{else}}
  それ以外
{{/if}}
です。
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",age: 14},
{"name": "綾波レイ",age: 29},
{"name": "ゼルエル",age: -1}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

合わせて「AND条件は &&」、「OR条件は || 」で実現可能であることが分かりました。

boolean

ここまで来ると、どうやら直感で使うような普通の機能は全部備わっているということが分かってきました。
一応、「true」「false」といったboolean型の動作も確認してみましたが、こちらも何ら問題は起きないようです。

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{if flg}}
  {{:name}}
{{/if}}
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",flg: true},
{"name": "綾波レイ",flg: false},
{"name": "ゼルエル",flg: true}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>


ロジック入り

極め付けはコレ。

if文の中にJavaScriptのロジックを入れてしまうという。

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
{{:name}}は
{{if age.substr(0,1) == 1 }}
  10台
{{else age.substr(0,1) == 2}}
  20台
{{else}}
  それ以外
{{/if}}
です。
</div>
</script>

<script>
var data = [
{"name": "碇シンジ",age: "14"},
{"name": "葛城ミサト",age: "29"},
{"name": "ゼルエル",age: "-1"}
];

var template = $.templates("#jsRenderTmpl");

var htmlOutput = template.render(data);

$("#result").html(htmlOutput);
</script>

「{{if age.substr(0,1) == 1 }}」みたいな記述も可能。
要するに、JavaScriptの機能がそのまま動くように作られているわけです。

ただし、JsRenderのif文にこういうロジックが入ってしまうとソースが複雑化してしまいます。

分岐が必要な場合はシンプルに記述出来るようJSON定義の設計を見直すことをオススメしますが、
諸々の事情で出来ない場合等は、こういう小技で乗り切るのもエンジニアの現場判断と言えるでしょう。

終わりに

次回は同じく基本中の基本、「for文」の書き方をご紹介します。

2014年10月3日金曜日

【JsRender】JSON定義

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

現在はJavaScriptによる画面レンダリングツール「JsRender」について連載しています。
今回のテーマはJSONです。

JSONデータ定義

さて、前回は単純な「ただ文字列を表示するだけ」という基本についてご紹介しました。

ここからif文やfor文など様々な機能に行きたいわけですが、その前にJSONの定義方法について検証したいと思います。

シンプル

一番シンプルなのが前回のこれ。

Scrpit

<script id="jsRenderTmpl" type="text/x-jsrender">
私の名前は{{:name}}です。
</script>

JSON

var data = {"name": "遠藤 太志郎"};

これで「私の名前は遠藤 太志郎です。」になります。

配列

次に配列に行ってみます。

Scrpit

<script id="jsRenderTmpl" type="text/x-jsrender">
<div>
私の名前は{{:name}}です。
<div>
</script>

JSON

var data = [
{"name": "遠藤 太志郎"},
{"name": "えんどう たしろう"},
{"name": "エンドウ タシロウ"}
];

結果がこちら。



ふ~む……。
どうやら導入データが配列になっていると、自動的にループでやってくれるようですね。

でもこれ、本当に単純なデータをベロベロ出すだけなら良いけど、
例えばゼロ件の時はメッセージを出すとか、僅かでも工夫が必要になると途端にデータ定義が不便になっちまうんですよ。

単純配列の出番は本当にシンプルな場合のみです。
まあ、配列にはこういう機能があるとだけ覚えておけば良いでしょう。


入れ子

JSON定義ってオブジェクト指向的な性質を持っていますから、JavaのクラスをJSONに置き換えるようなイメージで
定義することもできます。

こんなようなクラスがあるとしますと、

public class Person {

    /** 名前 */
    private String name;

    /** 年齢 */
    private int age;

}

JSONで書けばこうなります。

var data = [
var data = {person:{"name": "遠藤 太志郎",age:28}};
];

この場合、テンプレートはこうやって書く。

<script id="jsRenderTmpl" type="text/x-jsrender">
私の名前は{{:person.name}}です。年齢は{{:person.age}}です。
</script>

「.(ドット)」で連結すれば、JSONの階層構造を掘り進んで読んでくれるわけです。
これがJsRenderの良い所で、JavaでBEAN定義したクラスを丸ごとJSON化して叩き込むことが出来ますので、ロジックが非常に楽になるのです。
JavaScriptの機能がそのまま踏襲されています。

配列番号指定

次は「入れ子と配列の合体で番号指定」です。

以下みたいに入れ子構造の先が配列になっている場合です。

var data = {person:{"name": ["遠藤","太志郎"],age:28}};

nameの属性に「苗字」と「名前」が別々に入っていますね。
こんなデータ構造になってしまうのは余り良いサンプルとは言えませんが、
仮に「firstname」「familyname」と別々のフィールドに定義しますと、それだけでJSONもデータ量が増えてしまいます。

「転送データ量削減の為に定義を省略する」など、諸々の事情で配列でやらなきゃならないタイミングもあります。

こういう状況で、「配列のゼロ番目に入っている苗字部分だけを取り出したい」という需要があるとします。
その場合はこうやって記述すればOKです。

<script id="jsRenderTmpl" type="text/x-jsrender">
私の苗字は{{:person.name[0]}}です。年齢は{{:person.age}}です。
</script>

[0]で順番指定出来るわけですね。
痒い所まで手が届く便利設計になっています。

ちなみに「苗字+名前」としたい場合は「{{:person.name[0]}}{{:person.name[1]}}」と
単に続けて書けばOKです。

文字番号指定
最後に小ネタを。

JsRenderって、「文字列の何番目だけを出したい」という文字番号指定機能があるのです。

JSONデータをこれとします。

var data = [
var data = {person:{"name": "遠藤 太志郎",age:28}};
];

そしてこう書くと。

<script id="jsRenderTmpl" type="text/x-jsrender">
私の苗字は{{:person.name[0]}}{{:person.name[1]}}です。年齢は{{:person.age}}です。
</script>

これでもちゃんと「遠藤」ってなります。


  • {{:person.name[0]}}=遠
  • {{:person.name[1]}}=藤


この辺りもJsRenderの機能と言うより、JavaScriptの仕様なんですけどね。

JavaScriptには偶に変わった仕様が入っていることがあるのです。
配列と見間違えてバグの温床を化すのがオチなような仕様ですけれども、
テクニシャンな人は使ってみると良いでしょう。

終わりに

以上でデータ定義編は終わりです。
JavaScriptの標準に乗っ取った、直感的に理解出来る定義方法になっていると思います。

次回もJsRenderは続きます。