@minop1205関数の実行結果をバインディングに渡すループ内でViewModelに属する関数を使う際の注意バインディングにイベントハンドラを追加イベントハンドラに任意の引数を渡す2つの方法Knockout.jsでは、View(HTML)側のバインディングに対してViewModelオブジェクトのプロパティだけではなく、JavaScriptの関数を用いることもできます。textバインディングに関数の実行結果を渡したり、clickバインディングにイベントハンドラを関連付けたりすることが可能です。今回は、そのようなView側での関数の使い方についてまとめてみました。関数の実行結果をバインディングに渡す■引数なしでの呼び出しまずは最も基本的なケースで、ViewModelオブジェクトに属する関数(ViewModelオブジェクトのメソッド)を引数無しで呼び出し、その実行結果をバインディングに渡す例です。注意する点も無く、通常の関数呼び出しと同じです。下記のコード例では画面に「Taro」と表示されます。};ko.applyBindings(viewModel);■引数を渡して呼び出し次に関数に引数を渡す場合のコードですが、この場合も通常の関数呼び出しと同じなので、特別注意することはありません。Taro」と表示されます。};ko.applyBindings(viewModel);■ViewModel外の関数の呼び出しView側で用いる関数は、必ずしもViewModelオブジェクトに属する関数である必要はありません。次のコード例の様に、グローバルスコープ(windowオブジェクト)から辿ることができる関数ならばView側でも使用可能です。ko.applyBindings();};本来、ko.applyBindingsメソッドにはViewModelオブジェクトが渡されますが、上記コード例の場合、ViewModelオブジェクトを一切使用していないので、6行目のko.applyBindingsメソッドは引数無しで実行しています。すると、そもそも6行目のko.applyBindings()は不要に思えるかもしれません。ko.applyBindings()を呼び出さないとView側でバインディングが有効にならないので、ViewModelオブジェクトの有無にかかわらずko.applyBindingsメソッドは必ずコールする必要があります。通常、View側からViewModelオブジェクト(ko.applyBindingsメソッドの引数として渡したオブジェクト)を参照する際、ViewModelオブジェクトそのものが参照の基点となります。ループ(foreachバインディング)の内側でViewModelオブジェクトを参照する場合、「現在のアイテム(foreachバインディングが参照している配列の各要素)」が参照の基点になるということに注意する必要があります。次の様なViewModelオブジェクトがあったとします。};ko.applyBindings(viewModel);上記のviewModel.showNameメソッドを呼び出す場合、foreachループ以外の場所からは次の様に呼び出すことができます。ここまでは何も問題ありませんね。</ul></body>foreachバインディングの内側ではviewModelオブジェクトそのものではなく、現在のアイテム(上記のコード例のviewModel.namesプロパティの各要素)が参照の基点になるので、上記の例だとtaro.showNameなどという存在しないメソッドを呼び出すことになってしまうので、これはエラーになります。ループの内側からshowNameメソッドを正しく呼び出すためには、次のコードの様に「バインディング・コンテキスト」を使用し、現在のアイテムからの相対パス(パスという表現が正しいかどうかは分かりませんが)、もしくは絶対パスでメソッドを指定します。$parent.showName($data)"></li></ul>バインディング・コンテキストについては、以下で詳しく解説されています。日本語ドキュメントバインディングにイベントハンドラを追加バインディングにイベントハンドラを追加する場合は、バインディングに対して関数の実行結果を渡すのではなく、関数そのもの(関数オブジェクト)を渡す必要があります。me</button>これだと、myHandler関数の実行結果をclickバインディングに渡すことになるのでエラーになります。「myHandler()」ではなく正しくは「myHandler」です。};ko.applyBindings(viewModel);上記サンプルは、button要素をクリックした場合にイベントハンドラ(myHandler)が呼び出されるコード例です。ボタンをクリックすると「hoge」とアラート表示されます。■イベントハンドラに自動的に渡されるパラメータknockout.jsではイベントハンドラを実行すると自動的に2つのパラメータが渡されます。最初のパラメータはViewModelオブジェクトの「現在のアイテム」で、2つ目のパラメータはイベントオブジェクトです。「現在のアイテム」とは、先ほどループ内での関数の呼び出しの項でも説明しましたが、通常はko.applyBindings()メソッドの引数として渡したオブジェクトを指します。イベントハンドラがループ(foreachバインディング)の内側で呼び出された場合は、ループ対象である配列の各要素を指します。これにより、例えば「ループ内のどのボタンが押されたのか」といったことを特定することができます。イベントオブジェクトは発生したイベントに関する様々な情報を格納しています。このオブジェクトを使えば、例えば「どのキーが押されたのか?」といったことを判別することができます。イベントバブリングの制御を行うこともできます。これら2つのパラメータをハンドラ内で利用するには、ハンドラ内でargumentsキーワードを使うか、以下の様に関数の引数に明示的にパラメータを指定することで利用することができます。//dataには現在のアイテム、eventにはイベントオブジェクトが格納されます。};ko.applyBindings(viewModel);イベントハンドラに任意の引数を渡す2つの方法イベントハンドラ内で「現在のアイテム」と「イベントオブジェクト」へのアクセスの仕方は紹介しましたが、これ以外に任意のパラメータをイベントハンドラへ渡すことも可能です。バインディングにイベントハンドラを追加するには、バインディングに対して「関数そのもの」を渡す必要がある、と説明しましたね。そのため、例えばdata-bind="myHandler('任意の引数')"の様な書き方は出来ません。これだと「関数そのもの」ではなく、「関数の実行結果」をバインディングに渡してしまうからです。以下に紹介する2つの方法を利用すれば、任意の引数を渡しつつ、関数そのものをバインディングに渡すことが可能です。いずれの方法もknockout.js固有の機能などではなく、JavaScriptがもつ基本的な機能をうまく利用してこの問題を解決しています。任意の引数を渡したいイベントハンドラを内包(ラップ)した無名関数を作成し、それをバインディングに渡すことで、イベントハンドラに対して任意の引数を渡すことができます。簡単で分かりやすい方法ですが、View側で関数を定義することになってしまうのが短所とも言えます。me</button>■bind関数を使う方法JavaScriptの関数にはbindメソッドというものが存在します。これを利用することで任意の引数をイベントハンドラに渡すことも可能です。bindメソッドは、元となる関数を指定されたパラメータと関連付け(=バインド)し、新たな関数を返すメソッドです。このメソッドの第1引数は、新たな関数内のthisキーワードとして使用する値を渡します。第2引数以降は実際に渡したい任意のパラメータを指定します。2016年9月30日サイトマップ。