Open benjamingr opened 9 years ago
@benjamingr There are a number of excellent plugins that you can use, including:
These are well tested, and worth checking out.
Since there seems to be no apparent issue with KO per se, I'll close this, but please let me know @benjamingr if you think there's something you feel the KO core could be doing better. :grin:
Cheers
Hmm, it looks like all these are for arrays. I was thinking adding declarative method to observables - not arrays - as observables themselves are multiple values over time :)
@benjamingr You use any observable with these plugins by using the .extend({trackArrayChanges: true})
extender.
If you are doing an arbitrary transform, the “canonical” way is to use a computed.
I'm terrible at expressing myself :D I'm well aware of what computed observables are - I'm just saying it'd be super useful to have a more declarative way to create them - as in the examples in the original post.
Potentially aligning with ES observables would also be nice (but unrelated, maybe I'll open another issue after the next TC meeting).
Thanks @benjamingr – appreciate your tenacity :)
Would an extender along the following lines be what you've got in mind:
ko.extenders.transform = function(target, fn) {
return ko.computed({
read: () => fn(target()),
write: target,
owner: target
})
}
Then one can do things like x = ko.observable().extend({ transform: (r) => r.toLowerCase() })
... and other syntactic sugar.
Once could of course do this for specific transforms, but above feels like the generic case.
Well, writing ko.observable().extend({ transform: (r) => r.toLowerCase() })
, is very verbose :) A lot more than ko.observable(3).map(x => 2*x)
.
The interesting case is flatMap
, where you want to wait for a promise (like in Rx), this is the really interesting case:
// flatMap can be named something else
// can substitute $.getJSON for `fetch`, `$http.get`
y = ko.observable("5").flatMap(x => $.getJSON("/api/users/3"))`
Where the returned computed observable updates when the $.getJSON
call returns.
In general, these methods are super useful in observable libraries - just 3-4 methods would go a long way.
@benjamingr Ok, I think I get it... I'm with ya, now. :) Which functions were you proposing should be replicated by ko, and what's a good precedent?
Reopening to keep this alive and for discussion.
The two concerns I have are:
.map
, etc., on observableArrays.map
and .flatMap
and .reduce
and .reduceRight
, if these can easily be accomplished by e.g. something like the transform
extender above. In other words, my personal feeling is that the core library should be generic and flexible. But I am open to persuasion. :)The thoughts here are neat and are ending up being a blend between KO and Rx. Rx offers a bit more though in that you can compose multiple streams and so on. I use Rx heaps in my server-side C# code and toyed with using it for the client-side UI but ended up not doing so. For the flatMap() proposal, there are various discussions, including in the KO GitHub Wiki, about an "asyncComputed". I wrote my own which probably has many flaws. I would certainly like to see this sort of thing properly implemented once rather than each of us having our own slightly different versions.
But, how far should it be taken?
Is it possibly better to see what some of the KO/Rx libraries already do and see if one of them can be "blessed" as the library the community tends to use (for me I see this similar to how I made extensive use of @rniemeyer 's AMD Helpers library before components became a part of KO).
So, here is what I had in mind:
map/filter/flatMap/scan
, nothing to join observables in a terribly clever way, but the basic stuff is super useful. I'm thinking around 5-6 methods here.@benjamingr, I don't see how adding these methods would be that useful. But even if I'm wrong, this seems like a perfect opportunity for you to create a plugin.
Hey, I'm just wondering if there is any work done on computed observables having Rx like capabilities by being able to create descendent computed observables via
.map
.filter
.reduce
flatMap
etc.For example:
It sounds like a few extra lines of code could make programming the non-ui parts a lot easier with Knockout, it doesn't have to be a full reactive-extensions library like an old closed issue suggested - it would just help a lot with sugar since I often find myself writing:
Which is a lot clunkier and somewhat more error prone.