Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

JsViews入門

JsRender/JsViewsのチュートリアルを書いています。こちらもどうぞ→「jsviews チュートリアル」の検索結果一覧 - Do You PHP はてな

いい加減書かないと、絶対に書かないような気がしたので。。。

先日(といっても2ヶ月前)のJsRender入門 - Do You PHP はてなの続きです。
JavaScript製のテンプレートエンジンであるJsRenderを使うとJavaScriptでHTMLコンテンツを出力する(特にメンテナンス)のがかなり楽になるんですが、データが変更された場合に自動的に再描画してくれるわけではありません。
たとえば、JsRender入門 - Do You PHP はてなの"使い方"にあるサンプルに追記し、配列fruitsに要素を追加するようにしたものが以下のサンプルです。

<html>
<body>
<div id="list"></div>

<!-- 追加用のボタン -->
<button id="add">add</button>

<script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
<script src="js/jsrender.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
    var fruits = [
        { code: "01", name: "りんご" },
        { code: "02", name: "バナナ" },
        { code: "03", name: "パイナップル" }
    ];

    // 配列にデータを追加する
    $('#add').click(function() {
        fruits.push({ code: "99", name:"ドリアン"});
        // ※1
    });

    // ※2テンプレートを使ってレンダリング
    $("#list").html(
        $("#template").render(fruits)
    );
});
</script>

<script id="template" type="text/x-jsrender">
    <div>
        {{:#index+1}}: <a href="/fruit/{{>code}}/detail">{{>name}}</a>
    </div>
</script>
</body>
</html>

これをブラウザで開いてボタンを押下しても表示は変わりません。まあ、当然といえば当然なんですが。。。とりあえず、※2の部分を※1にも記述すると再描画されるようにはなりますが、なんかイマイチな感じです。

で、ここから本題。
このように、JavaScript側で持っている配列などのデータとテンプレートをリンクさせ、データに変更があったタイミングで自動的に再描画するためのライブラリがJsViewsです。

ただし、こちらもJsRenderと同様、


Warning: JsViews is not yet Beta, and there may be frequent changes to APIs and features in the coming period.

となっています。

使い方

JsRenderの流れと似ています。

  1. テンプレートを定義する(scriptタグ)
  2. JSONデータを取得する
  3. テンプレートに名前をつけて登録する
  4. データとテンプレートをリンクさせる

以下は上のサンプルにJsViewsを組み込んだ場合の例です。

<html>
<body>
<div id="list"></div>

<button id="add">add</button>

<script src="http://code.jquery.com/jquery.js" type="text/javascript"></script>
<script src="js/jsrender.js" type="text/javascript"></script>
<script src="js/jquery.observable.js" type="text/javascript"></script>
<script src="js/jquery.views.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
    // データの配列(もしくはオブジェクト)
    var fruits = [
        { code: "01", name: "りんご" },
        { code: "02", name: "バナナ" },
        { code: "03", name: "パイナップル" }
    ];

    $('#add').click(function() {
        // 配列fruitsを監視(observe)しつつ、要素を追加
        $.observable(fruits).insert(fruits.length, {
            code: "99",
            name: "ドリアン"
        });
    });

    // テンプレートに名前をつけて登録する
    $.templates({
        linkTemplate: "#template",
    });

    // テンプレートlinkTemplate(#template)と変数fruitsをリンクさせ、
    // レンダリング結果をid="list"に表示
    $.link.linkTemplate("#list", fruits);
});
</script>

<script id="template" type="text/x-jsrender">
    <div>
        <!-- data-link属性に注目! -->
        {{:#index+1}}: <a href="/fruit/{{>code}}/detail" data-link="name">※3</a> (<span data-link="code">※4</span>)
    </div>
</script>
</body>
</html>

JSONデータを更新する場合、おおまかに2つの流れがあります

  • 更新後のデータとテンプレートを再度リンクさせる
  • $.observable()を使って配列データを変更する

XHRでデータを取得して全データを差し替える場合は前者の方法が楽かと思います。

テンプレート内のdata-link属性

基本的にテンプレートはJsRenderと同じですが、特定の要素の値とデータをリンクさせたい場合、data-link属性を使います。

<script id="template" type="text/x-jsrender">
    <div>
        <!-- data-link属性に注目! -->
        {{:#index+1}}: <a href="/fruit/{{>code}}/detail" data-link="name">※3</a> (<span data-link="code">※4</span>)
    </div>
</script>

先ほどのサンプルのテンプレート部分ですが、2箇所ほどdata-link属性を付けています。こうすることで、リンクされたデータのnameプロパティの値が※3、codeプロパティが※4にそれぞれ自動的に埋め込まれてレンダリングされます。

で、ここからが超重要!
フォームの場合も同様にdata-link属性を付けることで、value属性を書かずにテキストを入力した状態にしたり、ラジオボタンを選択済みの状態にすることができますが、逆に入力フォームの値を変更することでリンク元JSONデータも変更されるようになります。
たとえば、先程のサンプルのテンプレートを以下のものに変更した後ブラウザで表示し、テキストボックスの内容やプルダウン、ラジオボタンを変更してみてください。そして、FireBugなどでfruitsの内容を確認してみてください。

<script id="template" type="text/x-jsrender">
    <div>
        名称:<input type="text" data-link="name" />
        コード:<select data-link="code">
        <option value="">選択してください</option>
        <option value="01">01</option>
        <option value="02">02</option>
        <option value="03">03</option>
        <option value="99">99</option>
        コード:<input type="radio" id="code{{:#index}}_01" name="code{{:#index}}" data-link="code" value="01" /><label for="code{{:#index}}_01">01</label>
        <input type="radio" id="code{{:#index}}_02" name="code{{:#index}}" data-link="code" value="02" /><label for="code{{:#index}}_02">02</label>
        <input type="radio" id="code{{:#index}}_03" name="code{{:#index}}" data-link="code" value="03" /><label for="code{{:#index}}_03">03</label>
        <input type="radio" id="code{{:#index}}_99" name="code{{:#index}}" data-link="code" value="99" /><label for="code{{:#index}}_99">99</label>
    </div>
</script>

ちなみに、同じデータにリンクしているプルダウンとラジオボタンは、たとえばプルダウン側を変更すると自動的にラジオボタン側も変更されます。

また、$.param(JSON.parse(JSON.stringify(fruits)))とかするだけでクエリ文字列やPOSTデータを作ったりできるようになります。項目数が多い画面を作ってると、この部分って単純作業なくせに面倒だったりしてたんですよ。。。javascriptコードもかなりすっきりします。

まとめ

ざっとですが、data-link属性が結構強力で、管理画面を作る際はかなり重宝してます。その他細かい機能については、デモを見てみてください。