fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
genekim 2021-06-28T16:32:51.295600Z

@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. 🙂

👍 4
😻 3
Jakub Holý 2021-06-28T16:37:15.295900Z

Thank you very much! It makes me happy to see it helps people.

jlmr 2021-06-28T17:06:06.296200Z

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.

jlmr 2021-06-28T17:07:03.296300Z

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!

2021-06-28T18:14:05.298Z

Have you looked into union queries for components? https://book.fulcrologic.com/#Unions

2021-06-28T18:14:17.298200Z

seems like the :widget/type would be your branch property

jlmr 2021-06-28T18:22:49.300600Z

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

Jakub Holý 2021-06-28T18:33:39.300800Z

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...)

jlmr 2021-06-28T18:40:20.303Z

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 ?

Jakub Holý 2021-06-28T19:07:33.303800Z

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?

jlmr 2021-06-28T20:01:48.305300Z

I think I don’t know enough about Fulcro yet ;-). But I was thinking about where to store the value of a text input.

Jakub Holý 2021-06-28T20:06:11.305500Z

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?

lgessler 2021-06-28T22:48:59.306800Z

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?

tony.kay 2021-06-30T19:17:44.315200Z

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.

👍 1
lgessler 2021-07-01T20:27:11.359600Z

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

lgessler 2021-06-28T22:51:37.306900Z

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