knockout.jsとそのプラグインのMapping(knockout.mapping)の組み合わせはすごく便利ですね。このあたりの詳しい話はしばやん先生のこちらのエントリを参照。 Knockout.js の Mapping プラグインを使ったら凄く捗った件 - しばやん雑記
localStorageとも相性バッチリ
つまるところ、knockout.mappingは以下の二者の間で相互変換をサクッと行ってくれます
- プレーンなJavaScriptのオブジェクト(及びそのJSONな文字列)
- (バインド可能なようにObservableなメンバで構成された)ViewModel
JSONとの相互変換も楽なので、RESTなWEB APIとのやり取りをスムーズにこなしてくれるのはもちろん、例えばフォームの内容をlocalStorageに出し入れする時などもすごく楽にできました。
例えばこんなフォームがあるとして:
<dl> <dt>name</dt> <dd> <input type="text" id="name" data-bind="value:name" /> </dd> <dt>age</dt> <dd> <select id="age" data-bind="value:age"> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> </select> </dd> <dt>email</dt> <dd><input type="text" id="name" data-bind="value:email" /></dd> </dl>
こんな感じでknockoutを使ってフォームとバインドしてやります:
var initData = { name: "foo", age: 20, email: "foo@example.com" }; // mapping JavaScript object to ViewModel by knockout.mapping. var viewModel = ko.mapping.fromJS(initData); // Bind ViewModel to input form by knockout.js. ko.applyBindings(viewModel);
Mappingプラグインを使ったいるのが var viewModel = ko.mapping.fromJS(initData);
の部分で、オブジェクトからObservableなモデルを自動作成してくれます。素敵。
フォームの入力内容をlocalStorageに保存する
ここで、入力された内容をlocalStorageに一時保存したいとしましょう。必要なコードはたったこれだけです:
var formData = ko.mapping.toJSON(viewModel) localStorage.setItem("formData", formData);
フォームにバインドされているviewModelからはフォームの入力内容が反映された値が取得可能です。これをMappingの機能を使ってJSONの形で受け、そのままlocalStorageにセットします。 一旦変数で受けてますが、1行でも良いですね。もちろんフォーム部品が沢山あっても必要な行数は変わらないでしょう。
localStorageに保存された内容を読みだしてフォームに反映する
ではlocalStorageから読み出すのはどうかというと、こちらはこうなります:
var json = localStorage.getItem("formData"); ko.mapping.fromJSON(json, {}, viewModel);
今度はlocalStorageから読み出したJSONを使って既存のマップ済みのViewModelを更新します。これも1行で書けますね。フォーム部品が沢山あっても(以下同文)。
まとめ
今回はlocalStorageを使いたい事情があったのでlocalStorageを例にしていますが、REST Web APIなどでも普通に利用できると思います(というかそもそもそういう目的で作られたものだと思います)。
knockout自体が軽量コンパクトなこともあり、『ページの一部だけをちょっと双方向バインドしたい』的な用途ではAngularJSよりも使い勝手が良いと思ってたりするのですが、Mappingプラグインがそれをさらに後押ししてくれるように思います。