きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

knockoutとMappingプラグインとlocalStorageは相性がいいかも

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プラグインがそれをさらに後押ししてくれるように思います。

 

フルバージョンのソースとデモサイト

フルバージョンのソースコードgithubに置いてあります。また、そのまま動くGithubページも置いてみました。