-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support of filters/projections for observableArrays #695
Conversation
Interesting idea. I like it. Technically you could already do it with a computed property, by using |
+1 :) |
Just a few notes for myself whenever I next think about this:
|
@SteveSanderson - Ideally this would be opt-in or we would recognize that there is someone interested in the callback to avoid unnecessary calculations. If it was built into |
Good ideas here. I have been working on some of these in my Knockout fork. I already have it set up to post Regarding |
Steve, I can provide you with a working code that adds an event system you were talking about in the comment above by intercepting every standard method of array. It is based on MicrosoftAjax library, but still may be worth looking at. P.S. By saying 'based on MicrosoftAjax' I mean uses its naming convention and event system (addHandler). |
Thanks! I think the implementation would be straightforward enough; it's just a matter of scheduling it alongside other priorities. |
What is the status of this? How is it prioritized @SteveSanderson, and have you got it to work @mbest? I feel this would improve the code for simple observableArray operations, and it would be a performance improvement over plain computed, which have to recompute the entire array if only one part of it changes. |
A knockout plugin that adds underscore or lodash Collection API to the observableArray would be a nice match IMO |
OK, I've started working on this. The overall plan I have in mind is:
Proposed APIsI'd appreciate any feedback on these designs:
Example usage:
Or:
Or:
As for the
Does this sound good? I'll submit a pull request that implements this soon. |
+1 for this! |
@SteveSanderson I'll look over your very detailed description soon. In the meantime, I want to share the work I did on this: https://github.com/mbest/knockout/compare/array-change-tracking |
@SteveSanderson, @mbest it would be great to support custom comparison function, as mentioned here #937, what do you think? |
Minor feedback that I have on this design:
|
map() and filter() should also have an optional second argument which would be used as the this value for the callback function. The Array's prototype object in ES5 also supports that argument for its map() and filter() methods, it would be easier to remember only one signature. |
We should also export the |
I want to add reduce and reduceRight to the list of built in functions. With reduce you don't need to recalculate all the items when a new item is pushed to the end of the array: only the last item needs to be run through the reduce function with the original array as the other input argument. The same would be true for reduceRight, but when an item is shifted onto the front of the array. |
… because it will be far cheaper for known operations
Currently only knows about "push"
Thanks for all the feedback! Ryan - agreed - have used those names. Michael - thanks for pointing me to your take on this. I've taken a bunch of your ideas from that code and adapted the APIs a bit to produce what I hope has a few extra advantages. Then I built sparse diffing on top of that. In particular the differences are:
Now with all this, I've also built a plugin called
Good point - we can ensure that is the case.
I'll check out how much extra code this adds to |
Actually, after further consideration, I'm wondering if Michael's "subscribe"-based API for receiving array changes might be a bit cleaner and more consistent with our other patterns. It eliminates both I've added a further commit that means this pull request now follows that API pattern. Usage:
One slight drawback is that it isn't so obvious how to get the current array contents inside your subscription callback. The way to do it of course is just to evaluate On balance I suspect this is better than the Now, this is a fairly low-level API that we probably wouldn't expect most developers to use anyway. The primary use case is really to enable "projections"-type plugins and possibly also for internal use inside KO. If it turns out that developers do use this a lot, we could consider adding a |
I prefer the |
A massive +1 for this feature in general, my use of observable arrays is falling down due to compareArrays and arrayMappingToDomNodeChildren grinding to a halt when my observable array grows to thousands of elements. Also I'd prefer the subscribe approach. I think the natural array methods such as push, and splice should get the benefits of understanding the details of the change to the array. |
This is excellent - thanks very much Michael! These are really great improvements. |
This looks fantastic. I use map/filter/reduce extensively, and think that it should be added to the core as soon as possible. Please consider adding 'some/every' method as well. |
Hi |
@lovedota please use formatting and indentation. It makes everything a lot easier to read. Hi I am working with JQGrid CustomBindings and using MBest function to do with this. If we can get the changed items, it will be good to use bindingAttributes.dataSource.subscribeArrayChanged(
function (value) { //Add New Item
$element.addRowData(value[rowId], ko.unwrap(value));
},
function (value) { //Remove New Item
$element.delRowData(value[rowId]);
if ($selectAllCheckBox.is(":checked") && dataSource().length === 0) {
$selectAllCheckBox.removeAttr("checked");
}
},
//NEED a callback to check if some item with Observable Property has changed
); |
The So we can do this:
It also works with arrays containing objects, with some caveats. You shouldn't rely on |
+1 for this feature, missed it a lot until now! @SteveSanderson: on your blog, you stated 'Coming soon: A powerful new plugin, built using arrayChange, for efficiently processing chains of maps and filters on observable arrays. Just as soon as I get permission to publish it :)' Is there any chance to get knockout.projections.js and test this plugin at the moment, or can you estimate how long it will take until it will be published? |
does anyone know when the mentioned knockout.projections.js plugin will be released? Steven seems too busy to answer my question at the moment, and I need the functionality of projected/efficiently filtered computed arrays very soon, otherwise I have to develop something for myself. Are there any problems with the plugin I could help solving (testing, API discussion etc.)? |
I'm also eagerly waiting for this feature |
I don't know any more than you. |
Hey, sorry for the lack of responsiveness since v3.0.0 was released! My wife gave birth last week, so as you can guess I'm off work and pretty focused on home stuff right now and for the next week or so. There have been a few emails flying round in my team trying to confirm it's all clear to publish knockout.projections (which is fully built, tested, and ready to go, and works really nicely!) to GitHub. I don't anticipate any problem with going ahead with open-sourcing it, so hopefully by the time I'm back at work the lawyers will have given approval. |
Steven, thank you very much for explaining the status of the plugin. Looking forward to see it on github in the near future. |
@SteveSanderson, congratulations. Your wife needs the rest, so it's great you're taking the time off. |
…nts to be bound (when there is no partial application).
I got the all-clear to publish I'll write a more detailed blog post when I get a chance, but for now, those of you who've been keen to try this out will be able to make sense of it. Let me know if you have questions, and especially if you discover any issues! Thanks. |
Nice one Steve, will try it out. |
thanks Steve, I'm looking forward to trying this out. |
@SteveSanderson - Thank you for this! Does this rely on knockout 3.0.0's arrayChange functionality, for the "efficient" part? It looks like it does from the source, so perhaps you should add that to the README? |
Evan - yes it does. On Tuesday, November 26, 2013, Evan Worley wrote:
|
This looks hellasweet! Can't wait to go refactor some of that logic out of my app code now! |
@SteveSanderson, @mbest - could you add links to knockout-projections, knockout-es5 and knockout.punches to plugin section on knockoutjs.com? |
@coryandrew1988 - you mentioned a (Overall, I am hoping that this will be useful for |
@MrAndMrsK Sorry for the late response. The code (written years ago, so it might need some updates) can be found here. |
@coryandrew1988 Thanks! (from MrAndMrsK) |
A common scenario where experience from usage of KnockoutJS can be improved is having an observableArray of elements that is not binded directly to HTML, but first projected to a set different items, or filtered by a condition.
Would be great to have something similar to:
var array = ko.observableArray([]);
var filtered = array.filter(function(item) { /* condition / });
var projection = array.select(function(item) { / selector */ });
Right now you can achieve this by using a computed observable, but this will mean that every item of resulting array will be tested against condition/selector if any item of initial collection changes, and thus whole array will be rebound, that is not effective in terms of performance.
The fact of recreation is itself crucial as it may result in the loss of state for items that were recreated, in the case it was a projection.