みなさんこんにちは。江口です。
今回は、Observable が提供している様々な拡張機能について紹介します。 Knockout のバージョンは執筆時点で最新の安定版の 2.3.0 です。
Observable の拡張
すべての種類の observbale には拡張機能を追加する機能が提供されています。この機能を利用すると、observable に対して新しいプロパティを追加したり、サブスクリプション関数を追加するといった処理をあらかじめ拡張機能として定義し、observable に組み込むことが可能になります。
拡張機能は、次の手順で利用する事ができます。
- ko.extenders に拡張機能を定義する
- observable.extend メソッドで拡張機能を呼び出す
例として、バリデーション機能を observable に追加するような拡張機能を作成してみましょう。
次のようなコードで ko.extenders に拡張機能を追加することができます。第一引数が拡張機能を適用する observable で、第二引数にオプションが渡されて呼び出されます。ここではオプションとしてバリデーションの判定を行う関数を指定できるようにしました。
ko.extenders.validation = function (target, validator) { target.isValid = ko.observable(validator(target())); target.subscribe(function (newValue) { target.isValid(validator(newValue)); }); return target; };
ここでは extend メソッドが呼び出された observable に対して、バリデーションの判定を行う関数を実行した結果を新たに追加した isValid プロパティに設定するようなサブスクリプション関数を定義しています。戻り値にはもとの observable を返しています。
上で定義した拡張機能を利用するには、observable の extend メソッドを呼び出します。次のように キーに拡張機能名、値にオプション(ここではバリデーションを行う関数)を指定します。
var validator = function (newValue) { return newValue.length > 0; }; self.todoSummary = ko.observable('').extend({ validation: validator });
以上のコードで、self.todoSummary の現在の値が0文字より大きいかどうかを self.todoSummary.isValid から取得することができるようになります。
ここの例では computed observable を利用することでも実現は出来ますが、同様の処理が複数箇所で行われるような場合には、拡張機能として定義して利用する事を検討するとよいでしょう。
throttle 拡張
拡張機能には標準で throttle 拡張が提供されています。throttle 拡張は、最後に observable の値が更新されてから一定時間が立つまで、実際に更新するのを遅らせることができる拡張機能です。頻繁に値が更新されることのあるような observable に利用することで、実際の更新頻度を抑える事ができます。
例えば、次のようなコードでは値を更新した 1 秒後に、実際の値が更新されるような observbable を作成することができます。
var text = ko.observable().extend({ throttle: 1000 }); text('hello'); // 1 秒遅れて hello に更新される
Backlog では、まとめて操作機能画面のキーワード検索でこの throttle 拡張を利用しています。これを利用することで、キーワードが入力される毎に検索を行うのではなく、ある程度まとまった入力が行われてから検索を行うことが可能となり、よりユーザの意図に近い検索キーワードでの検索がなるべく早く行われるようにしています。
カスタム関数の追加
observable のメソッドは 各 observable の fn プロパティに定義されているので、ここに新しいメソッドを追加すると observable からそのメソッドを呼び出すことが出来るようになります。
- ko.subscribable.fn
- ko.observable.fn
- ko.observableArray.fn
- ko.computed.fn
例えば、observableArray に対して filter や map などのメソッドを追加することでデータの加工や取り出しなどの処理を楽に記述できるようになります。
ko.observableArray.fn.filter = function(predicate){ return this.peek().filter(predicate); }; var array = ko.observableArray([1,2,3,4,5]); var odd = array.filter(function(v){ return v % 2 === 1; }); // 1, 3, 5
以上、簡単にですが Observable の拡張機能についての解説でした。次回は、各種バインディングについて解説する予定です。おたのしみに。