"event" バインディング
用途
event
バインディングは、関連付けられた DOM エレメントで任意のイベントが発生したときに、
指定した JavaScript 関数を実行するイベントハンドラを追加することを可能にします。
keypress
や mouseover
, mouseout
などどのようなイベントでもバインドできます。
例
<!-- View --> <div> <div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }"> カーソルをここに合わせて下さい。 </div> <div data-bind="visible: detailsEnabled"> なんらかの詳細メッセージ </div> </div>
// ViewModel var viewModel = { detailsEnabled: ko.observable(false), enableDetails: function() { this.detailsEnabled(true); }, disableDetails: function() { this.detailsEnabled(false); } }; ko.applyBindings(viewModel);
最初のエレメントにマウスカーソルが 乗る or 離れる と同時に、ViewModel の detailsEnabled
を切り替えるメソッドが実行されます。
2つ目のエレメントは detailsEnabled
の値の変化に応じて、表示/非表示 が切り替わります。
-
主パラメタ
プロパティを対象のイベント名、値を対象のイベントにバインドしたい関数にした JavaScript オブジェクトです。
どんな JavaScript 関数も使用できます。ViewModel の関数である必要は、必ずしもありません。
event: { mouseover: someObject.someFunction }
のように書くことで、どんなオブジェクトの関数も参照できます。 -
追加パラメタ
なし
(注1) ハンドラ関数に引数として“現在のアイテム”が渡される
ハンドラを呼び出す際、Knockout は第一引数として現在のモデルを渡します。 これは、特に配列の各要素を表示し、さらにどのアイテムの UI がクリックされたのかを知る必要があるときに便利です。
<ul data-bind="foreach: places"> <li data-bind="text: $data, event: { mouseover: $parent.logMouseOver }"> </li> </ul> <p><span data-bind="text: lastInterest"> </span> に興味がお有りですか?</p> <script type="text/javascript"> function MyViewModel() { var self = this; self.lastInterest = ko.observable(); self.places = ko.observableArray(['London', 'Paris', 'Tokyo']); // 第一引数として現在のアイテムが渡されるため、どの地名がマウスオーバーされたのかがわかる self.logMouseOver = function(place) { self.lastInterest(place) } } ko.applyBindings(new MyViewModel()); </script>
上記サンプルのポイントは2つあります:
-
foreach
やwith
の内部のように、 ネストされた バインディング・コンテキスト の中でルート ViewModel やその他親のコンテキストのハンドラ関数を呼び出す場合、 ハンドラ関数を示すために$parent
$root
といったプレフィックスを使う必要があります。 -
ViewModel にて、
this
の別名としてself
変数を定義すると便利です。this
を再定義することで、イベントハンドラや Ajax リクエストのコールバックで発生する 問題を事前に回避 することができます。
(注2) イベントオブジェクトにアクセスする、またはさらなる引数を渡す
場合によっては、イベントの DOM イベントオブジェクトにアクセスする必要がありますよね。 Knockout は、次の例のようにイベントオブジェクトを第二引数として関数に渡します。
<div data-bind="event: { mouseover: myFunction }"> ここにマウスをのせる </div> <script type="text/javascript"> var viewModel = { myFunction: function (data, event) { if (event.shiftKey) { // Shift キーが押されていた時のアクション } else { // 通常のアクション } } }; ko.applyBindings(viewModel); </script>
さらに引数を渡す方法として、まずハンドラを、引数を受け渡す関数リテラルでラップする方法があります。
<div data-bind="event: { mouseover: function(data, event) { myFunction('引数1', '引数2', data, event) } }"> ここにマウスをのせる </div>
Knockout は関数リテラルにデータとイベントオブジェクトを渡すため、ハンドラに渡すことができるということになります。
別の方法として、関数リテラルを View に記述するのは避けたいのならば bind 関数を使いましょう。 次のように、関数を呼び出す際の引数を指定することができます。
<div data-bind="event: { mouseover: myFunction.bind($data, '引数1', '引数2') }"> ここにマウスをのせる </div>
(注3) デフォルトのクリックの挙動を許可する
通常、Knockout はクリックイベントによるデフォルトの挙動を抑止します。
これは、もし input
タグの keypress
イベントを捕捉するために
event
バインディングを使用した場合、
例えば、ブラウザはハンドラ関数を呼び出すのみで input
要素の値を追加しません。
より一般的な例として、event
バインディングを内部で利用している
click
バインディング も同じくハンドラ関数を呼び出すのみで
リンク先への画面遷移を行いません。
通常は click
バインディングにてリンクは、ハイパーリンクではなく
ViewModel を操作するための UI 部品として使われるためこのような仕様となっています。
もしもクリックイベントのデフォルトの挙動を行わせたい場合は、
click
のハンドラ関数にて true
を返却してください。
(注4) イベントバブリングを抑止する
通常、Knockout はイベントが上位の要素のイベントハンドラにバブリングすることを許可します。
例えば、ある要素とその親要素がどちらも mouseover
イベントをハンドリングするとします。
このときこの要素がクリックされると、両方の要素にてハンドラが呼び出されます。
必要であれば、 (イベント名)Bubble
という追加バインディングに false
を指定することでバブリングを抑止することができます。
<div data-bind="mouseover: myDivHandler"> <button data-bind="mouseover: myButtonHandler, mouseoverBubble: false"> ここにカーソルをのせる </button> </div>
この場合通常であれば myButtonHandler
が最初に呼び出され、
イベントは myDivHandler
に遡及します。
しかし、付与された mouseoverBubble
バインディングの false
指定によってイベントの遡及は
myButtonHandler
を通過後に止まります。
依存
Knockout コアライブラリ以外、なし。