この記事は、knockout.js Advent Calendar 2015の5日目の記事です。 先に4日目に目を通すことを推奨しています。
knockout , knockout-es5 , knockout.punches環境を想定しています。
knockoutでは、標準で提供されているbindingのほかに、独自でbindingをcustom bindingとして登録することもできます。
custom bindingの作成の一例として、imgタグなどで用いることを想定とした、src属性を設定するbindingを作ってみます。
ちなみに、knockoutのbindingのattrの説明内でで、imgタグのsrcを<img src="http://example.com/{{imgfile}}">
としてはいけないのは、何故だか分かりますか?
そうです。src属性はjavascriptによって制御される前に、
ブラウザによって、外部リソースの取得の動作が実行されるため、
http://example.com/{{imgfile}}
へのHTTP Get Requestが発生してしまいます。
当然期待するファイルは存在しないので、リクエストエラーになりますし、それは無駄なリクエストです。(ネタ元、関連)
今回作成するcustom-bindingの仕様は次の通りとします。
-
data-bind="src:['http://example.com/',resource]"
のように、src
にresourceを解決するための配列を与える。 - src配列の1要素でも 未解決(undefinedまたはnull)の場合には、resourceを取得しない。
この場合のサンプルはこうなります。
<img data-bind="src:['http://lorempixel.com/',resource]"/>
ko.bindingHandlers['src']= {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var src = valueAccessor().map(function(item){return ko.unwrap(item)});
if(src.indexOf(undefined)==-1 && src.indexOf(null)==-1){
element.setAttribute('src',src.join(''));
}else{
element.removeAttribute('src');
}
}
}
Custom Bindingの解説は、(公式、日本語)に詳しく書かれています。
ko.bindingHandlers['src']
がsrc
という名前のcustom binding
を作成しますよー という宣言です。(最もただの連想配列として拡張しているだけなのですが)
updateは、vallueAccessor
の中値が変化したタイミング(および初期化のタイミング)で時効されるハンドラです。
valueAccessor()
は、今回の場合は、src:に渡す配列[]を取得しています。それの各要素を ko.unwrap()したものをsrcという変数に代入しているのは、コードを見れば明白ですね。
ko.unwrap
は、与えられた引数が、ko.observable()な関数であれば、それを実行した値 そうでなければ そのままの値を返すというヘルパーです。
その他の行は、ただのjavascriptとdom制御文なので説明は省きます。