-
Notifications
You must be signed in to change notification settings - Fork 27
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
Best approaches for dealing with sequences of items - items-view, keyed collections, etc. #23
Comments
I'm near to complete draft of my version of |
So, in terms of debugging and benchmarking, what I usually do is put |
I'd suggest we take the space here to describe approaches we're thinking of even if they're not fully implemented. One idea I have is a (bind-keys tag-kw attr-map? [key-expr keys-expr] & body) ;; keys-expr is implicitly wrapped in a `rx` Ex: (bind-keys :div [key (keys @my-map)]
(let [item-cursor (cursor my-map [key])
local-state (atom {:a 0})]
[:div (rx (:value @item-cursor))
(rx (:a @local-state))])) This would be the equivalent of: (rx
[:div
(for [key (keys @my-map)]
(let [item-cursor (cursor my-map [key])]
[:div (rx (str (:value @item-cursor)))]))]) Except that it only binds each key once and only once - so even if there's reordering, local state is preserved and new nodes don't need to be created. I think this approach is maybe half-way between what React does and what I was proposing for my To bind to a vector with this, you could write something like: (bind-keys :div [i (range (count @my-vector))]
(let [item-cursor (cursor my-vector [i])]
[:div (rx (str (:value @item-cursor)))])) What do you think? |
But when number of elements in map or vector changes, whole block will be rerendered? I like core idea of |
Hi Ruslan, So, what I am suggesting with bind-keys would be efficient - it would only On Mon, Dec 1, 2014 at 1:01 AM, Ruslan Prokopchuk notifications@github.com
|
In the README it says:
I've been playing around with DataScript and Freactive, with this kind of approach. There's two different things I came up with:
I don't really know how |
So I think either approach would work. The cursor approach would also give you something "atom-like". Observable collections would have special collection cursors which might be closer to your first approach. The idea with the observable collection is that it would let you manage a whole "collection" of entities so there would also be notifications when entities are added and removed... and individual entity cursors would be notified about changes to that entity only. My idea for observable collections is that basically they would basically be observable collections of observable cursors if that makes sense... I'm actually planning on posting a gist about this soon for discussion - I'll post the link here when I have it. |
Okay, here's a gist I posted of my ideas for observable collections (another one coming on the actual items-view soon): https://gist.github.com/aaronc/0654151190b9145dd473 |
Just posted this gist about the actual |
Arghh... PLEASE Ignore my previous comments about discussing this in the gist - gist does not support comment notifications - PLEASE discuss here instead. |
Hmmm... I was sure that I have posted my current |
I actually like your Also, please, describe how this kind of plugin could be implemented in freactive, it is fantastic (I mean using plugins as custom namespaced elements): [:freactive/items-view
{:items items
:container [:ul]
:template (fn [item] [:li @item])}] |
Well, the benefit of having observable collections exposed to the user is that it removes the need to do diffing when the collection is updated because you can track changes locally. i.e. when someone calls Something like what you are proposing - using a diffing library - would be useful in the case where people want to use plain old cursors and atoms, but I think would be significantly heavier in terms of code size and algorithmic complexity. Still, it's probably useful to have an implementation of observable collection based on diffing like what you've written. I can see a good use case say for someone who has existing business logic already based on regular atoms and cursors. In general, I think we should have By the way, for observable collections, I think now that |
Regarding custom namespaced plugins, it's pretty simple. When freactive gets a tag it does something like: (let [tag-ns (namespace tag)
tag-name (name tag)]
(if tag-ns
....
....)) So we can have strings or functions be registered as node and attribute namespace handlers - something like: |
Also, because |
Sounds very sweet (both observables and registering handlers for element namespaces), can't wait to see implementation! Will think how I can contribute to it. |
Okay so the most important thing right now is deciding on the right This is what I'm thinking of for the collection watch mechanism (updated from what I posted last night): (defprotocol IObservableCollection
"Defines the minimum protocol required for an observable collection
to be bound to an items-view."
(add-collection-watch [coll key f]
"Where f is a functional taking 3 arguments:
the key, the collection, a sequence of changes in the form of:
[[key1 new-value1]
[key2 new-value2]
[key3] ;; missing new value indicates the element was removed
]")
(remove-collection-watch [coll key])) Any comments? The advantages to this approach as I see it are:
A possible disadvantage is:
|
Hopefully this is the current thread for discussion on contributions to an items-view component? There seem to be 2 at the moment.
I'm building a collections-based UI at the moment. So I'd be keen on contributing any code that I can. I'll just need to get my head wrapped around the Observable concept. I see the ObservableCollection and it's usage. A) I have a use case where there's a list of items. And the system will need to drilldown on one particular item. Here, i) the list and ii) the drilldown detail are both views that are composed into a larger main view. I would need the render of ii) to depend on actions in i). Ie, if a user updates or adds an item, the single view ii) updates based on the selection of i). The current approach seems to assume that cursors for each item in i), will point to separate views. Is this correct? B) I'll also need to chain drilldown views. Can we cascade cursors? So can there be a iii) third view , with a cursor that depends on cursor ii)? C) Freactive's cursors seem to be similar to Om's Reference Cursors. I'm not sure if the items-view needs to consider some of the other use cases brought up in that library.
|
Hey Tim, so I'm not sure I understand the scenario you're describing in A) and B) but what I can say is that freactive observable collections would be able to wrap cursors and nested cursors. So we could have a scenario something like this: (def state (atom {:a {0 1 2 3} :b {4 5 6 7}}))
(def state-observable (observable-map state))
(def a (observable-map (get-cursor state-observable :a))) So Regarding the overall design, I want to reiterate that the observable maps & vectors and the For C), as I understand it every |
Ok, this is great. It definitely addresses points B) and C). Let me ask A) in a different way. Let's say I have a list of items, generated by freactive's list-view component. When I click on one of the items, what mechanism renders a "detail view", and binds a cursor to any DOM controls? Is that "detail view" rerendered (and mounted) on every click? Or is that detail view just changing based on a reactive atom, or some other thing? Also are you building items-view out, now? Can I help in any way? Thanks. |
Your sub-item will be generated by the I hope to build the |
Ok, that makes sense. Maybe this is an implementation detail. But the only other thing I'm wondering about, is where that :template (or :view) will get mounted onto the DOM tree. The current implementation is a function that generates the view structure. It's up to the calling code to insert that generated view into the DOM tree. I'm wondering how that will happen in this updated approach. If it's not yet decided, i) maybe a path to a DOM location? Or just providing a parent DOM id? |
So, my current design is to have the |
Ok cool.
So the _:container_ will be an ID to a mounted DOM node, into which items-view will mount the _:template_? The reason I ask is that my use case will have an existing DOM node in which I'll need to mount that :template view.
Ok awesome. |
Well |
My situation is that I have a list view and a details view which live side-by-side on the same web page. When a list item is clicked, I need the already mounted detail view DOM to be replaced with the contents of that _:template_. Does that make sense? I'd want to be sure that I can specify a location (the _:container_?) to a mounted DOM node, into which items-view will mount the :template. |
Okay, so I think these are two separate things. You don't need an items view at all for the details view if I understand what you are trying to do correctly. An items view is only for list view type things and the |
Correct.. kind of :) Isn't _:template_ what would provide that detail view rendering (tell me, if I'm wrong)? The core of my question is where the :template result (or its :container), gets mounted.
This is what I first attempted. Of course, changes in that detail view, need to get propagated back to the original item in the list view (using a cursor). I thought the only way to seed a cursor into a detail view, would be to re-render that view, with a new cursor to the selected item. If DOM nodes are listening to a cursor, simply resetting that cursor will update the DOM nodes? |
Take this for example: [:ul
(for [i [0 1 2 3]]
[:li i]] This code would generate the exact same DOM except that it is reactive - i.e. the text of each (def my-data (observable-vector (atom [0 1 2 3])))
(items-view
{:container [:ul]
:template (fn [item-cursor] [:li item-cursor])
:items my-data}) You can definitely share cursors between views and yes changes to the cursor in any location should propagate to both views. You could have a selected item atom or cursor which points to the key or to the selected cursor itself that the detail view is bound to. Everything bound to state should respond reactively to changes in that state. |
A ha, so that was my misunderstanding. That makes sense now. I'll try it out and let you know how I do. Thanks for the feedback :) |
'items-view' doesn't seem to work so far, but I might be doing it wrongly. I'm trying out the develop-branch:
No error, no warning, but no items as well (empty). Seems logic when I look at the source code. Am I doing something wrong or is items-view not working yet? - ObservableCollection (or TransactableCollection) is not present in the develop-branch, which makes me believe someone is working hard to get the job done. Just wondering what the status is, how it might be implemented and how to get it out of experimental status :p. |
Nope, items-view and also the observable collections are not really On Tue, Apr 14, 2015 at 4:06 AM, qsys notifications@github.com wrote:
|
Allright, good to know... I'll stick with the existing stuff. Thx! |
Hi, First of all, I just wanted to say that freactive is a joy to use and I wanted to thank you for the time you've spent on making it so well-engineered and well-thought-out. Just one thing - I'm trying to get conditional rendering to work. It seemed to work in release 1.0 (ignoring the fact that sometimes the watches were dropped, which is why I moved to the dev version), but now the following code doesn't render anything at all besides the enclosing div, even when
Also note that I modified the way freactive renders styles - I have virtual CSS being applied initially based on the element tag via a modification in the Do you know why this code wouldn't render as expected (i.e., as many divs as there are keys in the atom |
Looks like you have a typo there - shouldn't FYI, there is now a proper "items view" in the dev branch. Not really documented yet, but you could write: (freactive.macros/cfor [cur docs] ;; cur is a child cursor for each kv-pair in docs
[:div (str "K is " (freactive.core/cursor-key cur))]) |
Thanks so much! That was a pretty stupid typo on my part — I'm going to chalk it up to the fact that I have a fever today. Thanks for the hint about the items view too — it works great! |
No worries, hope you're feeling better! |
No description provided.
The text was updated successfully, but these errors were encountered: