カスタムバインディングの作り方

これはKnockoutJSアドベントカレンダー14日目の記事です。


KnockoutJS Advent Calendar 2014 - Qiita


KnockoutJSではすでに組み込まれているvalueバインディングやclickバインディングなど以外でも
自分でバインディングを作成することができます。

作り方は公式サイトにあります。
Knockout : Creating custom bindings


使い方は公式サイトのとおりです。


こういうふうに定義すると・・・・

ko.bindingHandlers.yourBindingName = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.
    }
};


こういうふうに使用できます。

<div data-bind="yourBindingName: someValue"> </div>


カスタムバインディングでは init と update のメソッドがあり、
初回時のロードで init 、 カスタムバインディングに適用した要素や依存しているobservables/computedsに更新があれば updateが実行されます。

よく使うメソッドの引数は以下のような感じです。

element
要素自体が渡されます。

valueAccessor
この要素にバインドされているViewModelのプロパティをメソッドで渡されます。
データを取得するには valueAccessor() のようにして取得します。

allBindings
この要素に対してdata-bindで渡されたすべてのデータが渡されます。


基本的な使い方は以上ですが、カスタムバインディングの実行前に実行されるメソッドも定義することができます。

ko.bindingHandlers.<name>.preprocess(value, name, addBindingCallback)

要素が使用されなくなったときに破棄したい場合は以下を使用すると良いです。

ko.utils.domNodeDisposal.addDisposeCallback(node, callback)

公式ドキュメントではそれぞれここに記載されています。
Knockout : Extending Knockout's binding syntax using preprocessing

Knockout : Custom disposal logic



最後に、だいぶ汚いコードですがサンプル書いてみました。
BootstrapのPopoverを使ってメモボタンをカスタムバインディングで書いてみました。


Examples

<a href="#" class="memo-btn" data-bind="memo:{ editable:true, target: 'memo1', content: memo1()}" data-placement="right" tabindex="-1" role="button">メモ</a>
<input type="hidden" name="memo1" data-bind="value: memo1"/>

上記のように memo というバインディングハンドラを書いて中にオブジェクトで設定を渡しています。
1つ目の引数 "editable" は編集可能かどうか
2つめの引数 "targe" は保存時に更新するViewModelのプロパティ名
3つめの引数 "content" はPopoverに表示する値
のようにしています。

ちょっとした応用ですがこのように引数をオブジェクトで渡すことで設定値とかも渡せるので便利です。
また3.2では ここ で書いた Componentsを使うとさらに簡潔に書くことができます。

明日も自分です。書き溜めてた分がなくなったので頑張ります。