libro
www.tuyano.com
JavaScriptで作ろう! Windows 8 アプリ・プログラミング入門

設定の保存とバインディング (3/3)

作成:2012-12-01 14:11
更新:2012-12-01 14:17

■データのバインディング

設定データの読み書きはこれで行えるようになりました。しかし、こうした設定データというのは、たいていアプリの表示などに関するデータだったりします。つまり、保管されている値はそのまま画面表示のタグの値や属性に設定されるだけだったりするのですね。

例えば、先程のサンプルも、入力フィールドのvalueid="msg"<div>タグのスタイルシートの属性に設定データが使われていました。こうした「表示の属性などの値を設定として保管する」というのであれば、もっと簡単に保管データを必要なタグに設定する方法があります。それは「データのバインド」を利用するのです。

バインドというのは、データと表示用のタグの各種値を関連付ける処理です。これにより、指定のデータがそのまま表示用タグの属性値に設定されるようになります。値を設定するスクリプトなどを呼び出す必要がないため、非常に手軽に設定データを表示に反映させることができます。

この「データのバインド」は、実は既にやっています。リストビューを使うとき、配列データを表示用のタグにバインドし、テンプレートを用いで項目を自動生成させました。あれもバインドの一種です。ただし、設定データの場合は、テンプレートなどは使いませんし、使用するオブジェクトなども微妙に異なります。(が、基本的な考え方は同じです)

このバインドは、設定情報でのみ利用するものではありません。単純に「ある値を自動的にHTMLタグの属性などに割り当てる機能」です。したがって設定情報のみならず様々なケースで利用することができます。――では、データのバインドの基本について整理しましょう。

●バインドされるタグにdata-win-bind属性を用意する
バインドでは、値を割り付けるHTMLタグ側に準備が必要です。それは、割り付けるそれぞれのタグに「data-win-bind」属性を用意する、という点です。これは以下の様な形で記述されます。
data-win-bind="値を割り当てる属性などの指定 : 値 "
値は、通常、連想配列などの形で用意されますので、「使用するキー」を書いておく、と考えればよいでしょう。例えば、 data-win-bind="name:savedvalue" といった具合に指定したならば、バインドする連想配列からsavedvalueの値を取り出し、そのタグのname属性に割り当てることになります。

●スクリプト側でWinJS.Binding.processAllを実行する
バインドの実行は、WinJS.Bindingというオブジェクトにある「processAll」というメソッドを使います(デフォルトで生成されているWinJS.UI.processAllとは、メソッド名は同じですがオブジェクトが違います。間違えないように)。これは以下のようにして呼び出します。
WinJS.Binding.processAll( バインドするDOMオブジェクト , 割り当てる値 );
第1引数には割り当てるタグのDOMオブジェクトを、第2引数には割り当てる値をそれぞれ指定します。割り当てるタグは、data-win-bind属性を用意したタグである必要はありません。それを含むタグであればOKです。あるタグのDOMを指定すると、そのタグ内にあるすべてのタグを検索し、data-win-bind属性があるものをすべて見つけてバインドしてくれます。また割り当てる値は、通常は名前を指定して値を取り出せるよう連想配列の形でまとめたものになります。

では、実際の利用例として、先程のサンプルをバインド利用の形に書きなおしてみましょう。下のリスト欄に修正リストを掲載しておきました。ここでは、<div id="msg">タグを以下のように記述してあります。
<p id="msg" data-win-bind="style.color: color; style.background: bgcolor; 
    style.fontSize: fsize">this is list sample page.</p>
data-win-bind属性で、style.colorstyle.backgroundstyle.fontSizeの3つの属性に値をバインドしています。このように1つのタグに複数の値をバインドさせる場合には、セミコロン(;)で複数の値をつなげて記述します。

また、入力フィールドについては、それぞれのvalue属性にdata-win-bindで値をバインドしていることがわかります。では、これらに値をバインドするスクリプト処理はどうなっているでしょうか。
var bindmsg = document.getElementById("msg");
WinJS.Binding.processAll(bindmsg, props);
var bindtable = document.getElementById("table1");
WinJS.Binding.processAll(bindtable, props);
実にシンプルですね。ID"msg""table1"のDOMオブジェクトを取得し、それぞれにWinJS.Binding.processAllで連想配列propsをバインドします。id="table1"は、それ自身にはdata-win-bind属性はありません。テーブル内の<tr>タグ内の<td>タグ内の<input type="text">タグに用意されているだけです。が、これでちゃんと値がバインドされるのです。

「だったら、<body>タグをバインドすれば一度に全部バインドされるんじゃない?」と思った人。その通り! これだと1回のprocessAllですべてのprocessAllがバインドされます。ただし、含まれているすべてのタグをチェックしていくわけで、それだけバインドに時間がかかるのは確かでしょう。また、内容の異なる複数のデータをバインドするような場合には誤った値がバインドされる危険もあります。その状況に応じて、「どの部分をバインドに指定すればいいか」を考えるようにしましょう。

※プログラムリストが表示されない場合

AddBlockなどの広告ブロックツールがONになっていると、プログラムリスト等が表示されない場合があります。これらのツールをOFFにしてみてください。

●プログラム・リスト●

※HTMLの<body>タグ
<body>
    <h1 id="title">Sample Page</h1>
    <p id="msg" data-win-bind="style.color: color; style.background: bgcolor; style.fontSize: fsize">this is list sample page.</p>
    <table id="table1">
        <tr><th>color:</th><td><input type="text" id="color" data-win-bind="value: color" /></td></tr>
        <tr><th>bgcolor:</th><td><input type="text" id="bgcolor" data-win-bind="value: bgcolor" /></td></tr>
        <tr><th>size:</th><td><input type="text" id="fsize" data-win-bind="value: fsize" /></td></tr>
        <tr><th></th><td><button id="button1">Save</button></td></tr>
    </table>
</body>


※JavaScriptのスクリプト

(function () {
    "use strict";

    WinJS.Binding.optimizeBindingReferences = true;
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;

    var applicationData = null;
    var localSettings = null;
    var container_key = "my_sample_app";

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.
                ApplicationExecutionState.terminated) {} else {}
            args.setPromise(WinJS.UI.processAll().then(function completed() {
                applicationData = Windows.Storage.ApplicationData.current;
                localSettings = applicationData.localSettings;
                if (!localSettings.containers.hasKey(container_key)) {
                    localSettings.createContainer(container_key, Windows.Storage.ApplicationDataCreateDisposition.Always);
                    saveProperties({ 'color': 'white', 'bgcolor': 'black', 'fsize': 14 });
                }
                var props = loadProperties();

                // データのバインド
                var bindmsg = document.getElementById("msg");
                WinJS.Binding.processAll(bindmsg, props);
                var bindtable = document.getElementById("table1");
                WinJS.Binding.processAll(bindtable, props);

                document.getElementById("button1").addEventListener("click", button1Action);
            }));
        }
    }

    app.oncheckpoint = function (args) {}

    // ※追加した関数
    function button1Action(event) { 略 }
    function loadProperties() { 略 }
    function saveProperties(props) { 略 }

    app.start();
})();
※関連コンテンツ

「JavaScriptで作ろう! Windows 8 アプリ・プログラミング入門」に戻る