@holyjak Wow! Thank you so much for writing these Fulcro tutorials and exercises. I found them to be incredibly illuminating, and marvel at how I managed to write anything at all without understanding fully these concepts. I think the documentation and tutorials are superb! https://github.com/fulcro-community/fulcro-exercises (Can’t wait to resume work on them this afternoon — I just finished Task 2. 🙂
Thank you very much! It makes me happy to see it helps people.
Ok so I am quite stuck with a project in Fulcro. Probably I’m trying something to ambitious for my current skill with Fulcro, but hopefully someone here can help me out. Earlier @holyjak gave me some pointers but unfortunately I haven’t gotten any further. I’ll elaborate more in a thread.
Basically the user can define nested widgets, which I store server side in the database (crux). Right now these widgets look like this in the database:
{:crux.db/id "some-long-id-for-this-widget"
:ent/type :widget
:widget/type :container
:widget/opts {:direction :vertical}
:widget/children ["some-other-id-for-that-widget" "and-another-id-for-widget"]}
I have a Pathom resolver that looks like this:
(defresolver widget-resolver
[{:keys [db]} {:widget/keys [id]}]
{::pc/input #{:widget/id}
::pc/output [:widget/type
:widget/opts
{:widget/children [:widget/id]}]}
(ffirst (crux/q db
'{:find [(pull ?widget [:widget/type
(:widget/opts {:default {}})
{:widget/children [(:crux.db/id {:as :widget/id})]}])]
:in [id]
:where [[?widget :crux.db/id id]
[?widget :ent/type :widget]]}
id)))
This will get a widget by id and output it in the form:
{:widget/id "some-long-id-for-this-widget"
:widget/type :container
:widget/opts {:direction :vertical}
:widget/children [{:widget/id "some-other-id-for-that-widget"
:widget/id "and-another-id-for-widget"}]
}
I’m stuck with how I make a “master” Widget component in Fulcro that renders the widget based on the type. Ideally each type would have its own Component that can be supplied with an :initial-state fn. Widgets can be recursive, so the widget with id "and-another-id-for-widget"
could have other :widget/children
as well and so on.
Should I change the way widgets are stored in the database? Do I have to change the resolver? Earlier attempts led to all kinds of errors. I know I have to use recursive queries, and possibly unions as well, but I’m unsure how to combine the two.
Any help is appreciated!Have you looked into union queries for components? https://book.fulcrologic.com/#Unions
seems like the :widget/type
would be your branch property
Ive looked at those but haven’t gotten my head around it yet. It seems like those work with the presence of keys in maps. Not values of a single specific key such as :widget/type
If all widgets have the same props then I would only have a single Widget component. However you could also make UI-only components for each of the types and manually use the right one based on the type: (defsc Widget [this props] {:query.., :ident :widget/id..} (case type :widget-a (ui-widget-a props)...) with stateless (defsc WidgetA [..] {} some-dom...)
The different widgets have the same props, but I might need different initial state and “ephemereal” state in the client. Is that possible as well with this approach @holyjak ?
Pre-merge might be a good solution for the "initial state" need though it's difficult to say without knowing why you need it. What do you mean by ephemeral state / what do you need it for? (m/set-field!..) would work just fine?
I think I don’t know enough about Fulcro yet ;-). But I was thinking about where to store the value of a text input.
Set-field would be a good solution I think. Did you go through https://fulcro-community.github.io/guides/tutorial-minimalist-fulcro/ and the associated exercises?
I have an entity with an ident, and the entity has an attribute that has a hiccup-like nested vector structure. if I want to use a fulcro component to render the nested structure, I need to give them all idents. where's the best place to do this? in pre-merge somehow, perhaps?
RAD may not handle it more gracefully depending on how you define your problem. What I was trying to get across is that your problem definition may be the problem. Storing UI as a first-class concern in a data model is sometimes necessary (esp when you get marketers involved 😉 ), but it is always way more complicated, and is very often overkill. Having a well-described data model that you can add metadata to (such as rendering hints) is way more effective and less complex. For example in RAD the form layout is very limited in the built-in UI plugin...you can just say:
[[:address/street]
[:address/city :address/state :address/zip]]
which makes street appear on line one, and the other 3 fields appear on line two of the form. It's super-easy to encode, but not very powerful....BUT, it is powerful enough for many many use-cases. This, compared to reifying all the diffs and CSS to accomplish the same responsive layout.Thanks for the patience and answers as always Tony, think I'll need to keep letting it stew what's best for my particular problem though it'll be easier now with your perspective
some more detail: it's not feasible to give each subvector an ident just based on the data it has alone, so i'd need to add a uuid or something