On Tuesday, April 21, 2015 at 11:43:12 PM UTC+10, Colin Yates wrote: > Yes, that is a valid reduction. Specifically my register-handler, > which only has access to db needs to know the result of f. > > The general principle of having my register-sub delegating to a defn > which is called from the register-handler is causing the pain because > there is actually a hierarchy of subscriptions going on here, so the > value of f might actually be resolving a chain of subscriptions. For a > simplified example: > > (register-sub :reference-data/locations) > (register-sub :reference-data/active-locations .. (reaction (subscribe > [:reference-data/locations)))) > (register-sub :page-1/location .. (reaction (if (following-defaults? > (-> db ...) @(subscribe [:reference-data/active-locations)))) > > the value of :page-1/location is of interest. > > > On 21 April 2015 at 14:27, Mike Thompson <[email protected]> wrote: > > On Tuesday, April 21, 2015 at 10:58:31 PM UTC+10, Colin Yates wrote: > >> Hi Mike - yeah, reading through I wasn't very clear. Let me try again > >> with a more fleshed out example: > >> > >> On the server there is a hierarchy, each node in that hierarchy may > >> contain some meta data for example: > >> :id - the unique id of the node > >> :type - indicating some semantics about that particular node > >> :current? - indicating whether it is still actively used or not > >> > >> Imagine there are 5 nodes and node 4, which is a leaf is not :current?. > >> > >> On the client I have a number of projections of this data: > >> - an "active" tree which prunes out all nodes that aren't :current?, > >> so there are 4 nodes > >> - an "everything" tree which shows everything, e.g. all 5 nodes > >> > >> In addition, every node in each tree is selected and there are > >> multiple instances of these trees. > >> > >> On the client (on a reporting page for example, where one of these > >> trees are in the filter) I need to know which nodes the user has been > >> selected. I have a handler, which in response to some event (either > >> the server indicating new data is available or the user changing some > >> data) which needs to know which nodes have been selected. > >> > >> If the user hasn't selected anything then the 'selected nodes' should > >> be the default set (i.e. all of the nodes). As soon as the user > >> changes the selection (by deselecting a node in the first instance) > >> the set of selected nodes is now every node that is selected (e.g. > >> every node apart from the one they just selected) and that instance of > >> the tree is no longer tracking the defaults. > >> > >> The server is free to send new config data at any point in time. When > >> this happens, the default set should be updated. The non-default set > >> that the user has changed should also be consolidated as well, but > >> that is different. > >> > >> Lets say my app state looks like: > >> > >> {:page-1 {:some-active-tree {:selected-ids [] :tracking-default? true} > >> :another-active-tree {:selected-ids [] :tracking-default? > >> true} > >> :some-all-tree {:selected-ids [] :tracking-default? true}} > >> > >> The user hasn't done anything so the selected-ids should be the > >> default sets (4 ids for :some-active-tree and :another-active-tree and > >> 5 ids for :some-all-tree). If the user were now to deselect node 2 in > >> :another-active-tree then app-state looks like: > >> > >> {:page-1 {:some-active-tree {:selected-ids [] :tracking-default? true} > >> :another-active-tree {:selected-ids [0 1 3] > >> :tracking-default? false} > >> :some-other-tree {:selected-ids [] :tracking-default? > >> true}} > >> > >> If they deselect node 3 in some-other-tree: > >> > >> {:page-1 {:some-active-tree {:selected-ids [] :tracking-default? true} > >> :another-active-tree {:selected-ids [0 1 3] > >> :tracking-default? false} > >> :some-other-tree {:selected-ids [0 1 2 4] > >> :tracking-default? false}} > >> > >> Should the server now update the config hierarchy changing node 4 back > >> to :current? and adding another node then at the very least the > >> 'selected nodes' for :some-active-tree should contain the ids of all 6 > >> nodes. :another-active-tree and :some-other-tree should also be > >> informed but they might not be updated depending upon the selections > >> (it gets more complicated...). > >> > >> At this point it is clear that one solution is to record a delta from > >> the defaults, but that only works because we are talking about > >> booleans; there are other non-boolean use-cases unfortunately. > >> > >> Another solution is to store the sets of defaults in app-state itself > >> rather than have it be a subscription and then overtime it changes > >> update the affected parts of app-state (:some-tree and > >> :some-other-tree in this example). > >> > >> This would be much easier if it was just dealing with rendering data, > >> in which case subscriptions are a perfect fit, but the set of data > >> needs to be sent back to the server periodically in a handler, and > >> handlers can't see subscriptions. > >> > >> To be frank, if anyone is still reading, my experience tells me that > >> if the problem is this hard to explain and requires this much > >> explanation then _I_ haven't understood it properly :), so I think I > >> need some more hammock time is in order. > >> > >> Thanks for anybody who hasn't lost the will to live yet ... :). > >> > >> On 21 April 2015 at 13:08, Mike Thompson <[email protected]> wrote: > >> > On Tuesday, April 21, 2015 at 4:52:05 AM UTC+10, Colin Yates wrote: > >> >> Hi, > >> >> > >> >> This is somewhat reframe specific, but how do people handle > >> >> default-values that can change? My specific use-case is that I have a > >> >> tree which can be expanded and collapsed. By default the tree should be > >> >> expanded to a certain level, however, as soon as the user manually > >> >> expands or collapses a node they should no longer follow the default. > >> >> The data the tree is displaying can change, meaning the defaults can > >> >> change over time. > >> >> > >> >> I can't simply define the defaults on startup because the defaults will > >> >> change over time. > >> >> > >> >> It can't be a subscription because the values need to be available in > >> >> the handler. > >> >> > >> >> My current thinking is that the app-db state has a 'follow-defaults?' > >> >> which is true by default but is set to false when the user explicitly > >> >> changes the state (e.g. by expanding or collapsing). When the > >> >> underlying hierarchy changes from the server, propagate that change to > >> >> all of the parts of the app-state that are interested. > >> >> > >> >> To be explicit, imagine I have the following template for tree: > >> >> {:expanded-ids [] :follow-defaults? true}. There are 6 instances of > >> >> this template in the app-db (i.e. 6 distinct UI trees). When the > >> >> server informs the client that the source-data has changed it then > >> >> updates each instance where follow-defaults?. > >> >> > >> >> I understand the rationale as to why subscriptions can't be in the > >> >> handlers but a subscription which switches on follow-defaults? seems > >> >> ideal. > >> >> > >> >> Maybe I could hack a UI-less component which reacts to that > >> >> subscription change by directly updating the underlying db... > >> >> > >> >> What would you all do? > >> > > >> > > >> > Hi Colin, > >> > > >> > I'm not sure I'm clear on the problem. Here's my attempt to explain back > >> > ... > >> > > >> > You have some setting (data) in your app (tree display state) which can > >> > be: > >> > 1. in a server-supplied state (you call this "default" state?) > >> > 2. optionally, in user-supplied state (if present, overrides 1). > >> > > >> > Over time, new versions of 1. arrive. If 2. exists, it always overrides > >> > 1. > >> > > >> > Have I understood? > >> > > >> > -- > >> > Mike > > > > > > Hmm. I don't get the specifics, but maybe we can talk abstractly ... > > > > You have values a and b which can change over time. And you have another > > value c which is a function (f) of a and b. > > > > (f a b) => c > > > > And, a b and c are all stored in `app-db`. > > > > And then when, say, 'a' gets updated (server? user?), you want to > > (reactively) modify the value in c again. After all, its value is a > > function of a and b, and a just changed? > > > > And you are reaching for `subscribe` as a way to sorta know when to rerun > > 'f' to recalculate new 'c'. > > > > Have I got it now? > > > > -- > > Mike
We have a similar situation with showing errors or warnings, because showing them or not tends to be a function of multiple pieces of other information in `app-db`. If 'this', but 'that' in set 'so-and-so', then show a warning saying "You have duplicates on X". And the values in 'this' 'that' and 'so-and-so' change over time. Going back to my abstract version of this involving 'a' 'b' 'c', our situation is that 'c' is some set of warnings which should be displayed to the user and 'a' & 'b' are the state which must be analyzed in order to figure out if we have warnings. (f a b) -> c So 'f' is some calculation on 'a' and 'b' to determine the value of our warning value 'c'. Our way of doing this is to run 'f' after every change. We use the 'enrich' middleware and we put it on every handler which could effect the values of 'a' or 'b' (we actually put it on every handler, just to be sure). So we don't even try to detect that 'a' or 'b' has changed. We just recalculate 'c' every single time. And we do it so that if the new 'c' tests equal to the old 'c', it doesn't get assoc-ed into `app-db`. This approach collapses the problem to being almost trivial. BUT it comes at the cost of re-running 'f' re-compuation each time anything changes (via enrich). In our case, it has beautiful reduced a pretty tricky bit of dependency updating. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/clojurescript.
