Fork me on GitHub

@tony.kay the book says that pre-merge runs as part of the app state initialization, but that’s not happening with multiple roots. Is that a bug, or just how things are?


not sure that is a correct statement.


roots all use the same code for init.


if you can confirm that it happens on the main root but not on multi-root, then it is a bug


Maybe I’m misunderstanding this section?


I’d have to review the code. That section was written by Wilker for F2. I didn’t write pre-merge, so I cannot tell you without looking into it.


but yes, the book claims that is the case


Ok. So initial state ends up being a real PITA with multiple roots. Basically, roots are overwriting shared data because their initial state is being applied each time a new root mounts, even if the data is already there. Pre-merge is really what I want in this situation, and it should work according to the book, but that’s not the behavior I’m seeing. I think I can work around this with a wrapper that does a merge-component on the root before it mounts. That will do for now, but this might be something we want to improve for multiroots down the road.


there is an optional initialize flag on register


it normally auto-detects based upon if that root type has ever mounted before so it does not repeat. You are not supposed to overlap data in an alt root initial state


but you’re right that perhaps a pre-merge behavior might be better


I don’t overlap data in the root itself. Basically each root is just a dummy that handles register/deregister and then renders a child, which is the real component. But some of those children query the same components, and those are getting overwritten.


so, the code used does invoke pre-merge behavior @mdhaney


I think I found the culprit - a component several levels deep that was doing too much in initial-state instead of pre-merge. Testing it now.


For those of you playing with RAD: I am rewriting how the save/delete stuff works into a proper middleware pattern. I knew I should have started with that, and it’s been biting me. The demo will be updated, but this will break things.

👍 8
Jakub Holý (HolyJak)09:02:48

Hi folks, how do you troubleshoot > main.js:2176 failed to load shadow.module.main.append.js #error {:message "Invalid join, {:alt0 nil}", :data {:type :error/invalid-join}} ? Obviously there is a problem with a query of a router target but the error does not indicate which router 😞


@holyjak I'm not sure what causes it but you could try removing all and adding them back one-by-one..

Jakub Holý (HolyJak)11:02:40

I found it was a routing target without :query , fixed by adding an empty one. Still, af anybody has tips how to find the culprit when I get such an error - other than a binary search - it would be appreciated.


well, a tip is that each target is initially composed (for initial state) with the router’s query in order. alt0 is the first composed target, alt1, etc.


or rather…alt0 is the first alternate (not the first), so alt0 is actually the second one…but I’ll just add a better error msg

Jakub Holý (HolyJak)23:02:31

Thank you! Also either the name of the router or/and the target component would be most helpful


Hey, could somebody have a look at ? I have no idea how to handle case, where I've got list of objects which might need to be handled differently (with different component) depending on their type. But then it turns out I will need some kind of OR in :query or something... How do you deal with such situation?


Union query is what you’re looking for


Oh, that's awesome. Thanks!


One thing I don't understand is how to create resolver returning union.


As it can return {:objects [:object/id :object/type :text-object/text]} or {:objects [:object/id :object/type :number-objext/number]}


(as seen from ::pc/output perspective.


Why not just return all the keys from the resolver?


What do you mean by “all the keys”? How should then pc::output look like?


{:objects [:object/id :object/type :text-object/text :number-object/number]}


I have a form that contains a query join to a normalized Thing, and I’d like to be able to change the reference, but I don’t need to change any fields in the thing itself. If I don’t add fs/form-config-join and :form-fields to Thing’s defsc then fs/add-form-config* throws an error: (throw (ex-info (str "Subform " (comp/component-name subform-class) " of " (comp/component-name class) " failed to initialize.") {:nested-exception e})) Is this a hard requirement for all query joins to have form stuff or is it maybe just a compilation error helper issue?


@thosmos If Thing’s join key is in form-fields, then it is a subform and must declare what should be tracked. If all you care about is identity, then just put the ID in the form-fields of this child.


the parent will then at track which Thing it points to, but nothing will be sent about THing itself


Yeah that’s what I’ve done, but I have a bunch of non-form components already, and it makes it more complicated to make a form version just for this. Does it make sense to only treat a key as a sub-form if that component itself has :form-fields? I’ve made a mod to fs/derive-form-info to do just this, but I won’t bother with a PR if it’s a hard rule and will break in other places.


+1. i tried to do the same, but it turned out to break some other parts of the form state flow (dirty fields maybe...), and eventually ended up rewriting half of fulcro form state ns would be great if you made it working!


ah yes after a few hours I see what you mean. I’ve just about rewritten half of form state! haha. To make it work I’d need to add some info about non-form joins to ::fs/config for doing dirty-fields


now that you mentioned it, i recall i’ve had this same issue with joins yeah... and prob decided that storing them in config was too flaky (as joins are also defined by the comp queries themselves and so could potentially go out of sync, dynamic queries maybe?)


well these are only the joins that are listed in :form-fields but do not themselves contain :form-fields so set of possibilities is much smaller than all joins? I think therefore it would be reasonable to put them in ::fs/config


ah, yeah, you’re right, sorry, haven’t touched form state for a while... guess then it’s all settled


well, thinking of dynamic queries, seems like form fields map would also need to be dynamic, currently the only way is to declare all the possible fields it seems


hmm, yeah one of my use cases would in fact be a form with dynamic queries … maybe I’ll wait on this until I get into implementing that …


but I would be OK with removing and re-adding the form-config when the query changes … so I would then want to be able to do (fs/set-form-fields Class fields-set) or maybe dynamically generate the form’s defsc from scratch …


i’d think that we could actually just allow :form-fields to be passed as a function (the same as :query), otherwise the sync logic would be split into a lot of places... i’ve had no use cases of dyn queries + forms myself though


oh yeah that’s a good idea


Sure, that is probably ok @thosmos.


OK if it works and passes tests I’ll let you know