"fn" で Observable に機能を追加
時には Knockout コアの変数型に新しい機能性を付加することで、コードをスリム化できると考えることがあるかと思います。以下のいずれかに対してカスタム関数を定義することができます:
ko.subscribable
に関数を追加すれば、継承により他の全てにおいて使用可能になります。ko.observable
に関数を追加した場合はko.observableArray
に継承されますが、 ko.computed
には継承されません。
カスタム関数を追加するには、それを以下の拡張ポイントの1つに設定します。
ko.subscribable.fn
ko.observable.fn
ko.observableArray.fn
ko.computed.fn
これにより、その時点以降に作成された同じ種類の全ての値でカスタム関数が利用できるようになります。
** 注: ** 本当に広範囲のシナリオで適用可能なカスタム関数でのみ、この拡張ポイントを使用するのが最善です。もし、一度だけカスタム関数を使用をする予定の場合は、これらの名前空間にその関数を追加する必要はありません。
例: observable array のフィルタされたビュー
こちらは filterByProperty
関数を定義して、その後に作成された全ての ko.observableArray
インスタンスで使用できるようにする方法です。
ko.observableArray.fn.filterByProperty = function(propName, matchValue) {
return ko.pureComputed(function() {
var allItems = this(), matchingItems = [];
for (var i = 0; i < allItems.length; i++) {
var current = allItems[i];
if (ko.unwrap(current[propName]) === matchValue)
matchingItems.push(current);
}
return matchingItems;
}, this);
}
この関数は元の配列を変更せずに残したまま、配列のフィルタされたビューを提供するための、新しく計算された値を返します。フィルタされた配列は computed observable であるため、元の配列が変更されるたびに再計算されます。
以下の動作例では、これをどのように使用できるかを示しています:
All tasks (3)
Done tasks (2)
- Find new desktop background
- Request more reggae music in the office
** ソースコード: ビュー **
<h3>All tasks (<span data-bind="text: tasks().length"> </span>)</h3>
<ul data-bind="foreach: tasks">
<li>
<label>
<input type="checkbox" data-bind="checked: done" />
<span data-bind="text: title"> </span>
</label>
</li>
</ul>
<h3>Done tasks (<span data-bind="text: doneTasks().length"> </span>)</h3>
<ul data-bind="foreach: doneTasks">
<li data-bind="text: title"></li>
</ul>
** ソースコード: ビューモデル **
function Task(title, done) {
this.title = ko.observable(title);
this.done = ko.observable(done);
}
function AppViewModel() {
this.tasks = ko.observableArray([
new Task('Find new desktop background', true),
new Task('Put shiny stickers on laptop', false),
new Task('Request more reggae music in the office', true)
]);
// Here's where we use the custom function
this.doneTasks = this.tasks.filterByProperty("done", true);
}
ko.applyBindings(new AppViewModel());
これは必須ではありません
もし、あなたが多くの observable array をフィルタリングする傾向がある場合、全てのobservable arrayに対してグローバルに filterByProperty
を追加すると、コードが整理されるかもしれません。しかし、時々しかフィルタリングの必要性がない場合、 ko.observableArray.fn
への追加を選択する代わりに、以下のように手動で doneTask
を構築するだけで済みます。
this.doneTasks = ko.pureComputed(function() {
var all = this.tasks(), done = [];
for (var i = 0; i < all.length; i++)
if (all[i].done())
done.push(all[i]);
return done;
}, this);