In my post Filtering Oracle JET ArrayTableDataSource I showed how to use an ojInputText to filter tabular data. In that post I mentioned using the knockout rateLimit extender, but shied away from it because rateLimit
'ing an observable attached to an ojInputText
rawValue throws the error, "rawValue option cannot be set" (even though rateLimit
'ing in this manner works). It is true that rawValue
is a read only field. For some reason, rateLimit
'ing an observable causes a write to the component property bound to the observable. This makes sense because that is the point of an observable: update something after the observable value changes. The problem is that rawValue
is read-only. I raised this issue with my colleagues and Jeanne Waldman shared this idea:
Create a pureComputed based off the rawValue observable and rateLimit the pureComputed.
Interesting. Jeanne's idea essentially creates a read-only observable that we can then rateLimit, effectively isolating rawValue
from a write attempt. Here are the JavaScript changes necessary to implement Jeanne's idea:
// ... other code above here ko.pureComputed(self.nameSearch) .extend({ rateLimit: { timeout: 250, method: "notifyWhenChangesStop" } }) .subscribe(function(newValue) { self.datasource.reset( filteredEmployees(newValue) ); }); // ... other code below here
Notice that we are wrapping the previously used nameSearch
observable in a ko.pureComputed
, extending the ko.pureComputed
, and then subscribing to the rate limited observable. Here is the jsFiddle:
Success! Our filter code now only runs 250 milliseconds after user input pauses. Considering our search algorithm, this will definitely perform better than invoking the algorithm for each key press. But is it as good as it could be? I'm not sure. We are now rate limiting a second observable rather than the primary observable. Will the primary observable continue to emit events with each key press? Did we trade an innocuous error message for some CPU/memory overhead? Does it matter? Normally, given two working solutions, I would choose performance, but I really don't want to see error messages cluttering my console.
Hi Jim, First off thank you very much for this post. It is exactly what i'm looking for. I'm having trouble getting it to work when fetching my data using $.getJSON. My data comes in just fine and i see the collection being filtered when i print to the console, but by datasource.reset is not filtering the results. When i hardcode the array, it works just fine. Would you have time to help me on this issue? The only difference between your example and mine is my JSON call:
ReplyDeletevar apptJSON = "http://host:port/appointments.json";
$.getJSON(apptJSON, function (data) {
$.each(data, function (i, item) {
self.appointments.push({
appointmentid: item.AppointmentId,
scheduled: item.Scheduled,
shipto: item.ShipTo,
shiptoaddress: item.ShipToAddress,
droptrailerorblank: item.DropTrailerOrBlank
});
});
});
Do you want to fork the Fiddle and update it with your changes? Then we can work on it together.
Delete