Knockout.js には text や value など、組み込みでバインディングが一通り用意されています。
これで十分かというと、そんなことはない。組み込みバインディングでは実現できない場面は多々あります。
例えば、ビューモデルが持っている DOM 要素を、ビューの DOM 要素に子としてバインドするやつとか。具体的には、先読みした画像をビューに表示したい。
Knockout.js ではカスタムバインディングを作れます。しかも結構手軽に。試しに、DOM 要素をバインドするためのカスタムバインディングを作ってみました。
<!DOCTYPE html> <html> <head> <title>Custom Binding Sample</title> </head> <body> <h1>Cutom Binding Sample</h1> <button data-bind="click: showMeat">ハンバーグ</button> <button data-bind="click: showSoup">スープ</button> <!-- dom カスタムバインディングを使って、 ビューモデルのプロパティを子要素としてバインドする。 --> <div id="main" data-bind="dom: image"> </div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script type="text/javascript" src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.js"></script> <script type="text/javascript"> (function() { // DOM 要素をバインドするカスタムバインディング ko.bindingHandlers.dom = { // 初期化。最初に1回だけ呼ばれる。 init: function(element, valueAccessor, allBindingAccessor, viewModel) { // ko.observable を取得 var value = valueAccessor(); // ko.observable から値を取り出す var valueUnwrapped = ko.utils.unwrapObservable(value); // 子要素をすべて削除 element.innerHTML = ""; // DOM 要素を追加 element.appendChild(valueUnwrapped); }, // バインドしたプロパティの値が変わったとき呼ばれる update: function(element, valueAccessor, allBindingAccessor, viewModel) { // やってる事は init と同じ var value = valueAccessor(); var valueUnwrapped = ko.utils.unwrapObservable(value); element.innerHTML = ""; element.appendChild(valueUnwrapped); } }; var app = { imageUrl: ko.observable(), showMeat: function() { this.imageUrl("http://img.f.hatena.ne.jp/images/fotolife/g/griefworker/20120303/20120303123605.jpg"); }, showSoup: function() { this.imageUrl("http://img.f.hatena.ne.jp/images/fotolife/g/griefworker/20120303/20120303121722.jpg"); } }; // 画像を表示する Image オブジェクトを取得 app.image = ko.dependentObservable(function() { var img = new Image(); img.src = this.imageUrl(); return img; }, app); ko.applyBindings(app); })(); </script> </body> </html>
さっそくブラウザで表示してみます。
最初は画像の URL を設定していないから、当然画像は表示されていません。
[ハンバーグ]ボタンをクリックすると
ハンバーグ画像が表示されます。旨そう。
[スープ]ボタンをクリックすると、
スープ画像に切り替わりました。実験成功。
上記サンプルはエラー処理とかまったく書いていない手抜き実装なので、実際に組み込むときはちゃんと作り込みます。それにしても Knockout.js でバインディングを簡単に作れてしまいましたね。この部分は本家の .NET を超えてるかも。