Fork me on GitHub
#fulcro
<
2023-11-12
>
Tobias Burger11:11:28

I have some difficulties defining the custom rendering of a to-many relationship. I've read the "Taking Over Rendering" section of the Fulcro RAD Developers Guide but I couldn't find a way how to render the subform (I think I'm missing something that connects the "single" form component with the to many cardinality but I can't get it to work. The Fulcro Demo has this relationship defined on the invoice where the :many line-items are referencing a single :ref item and the invoice form is the form I want to overwrite. For one I am interested on how to imitate the same form rendering as the auto generated one (with the buttons to add new items, or delete them. That would help me understand further details. And the other thing I am curios is on how to customize the subform even more. For example my new subform should render as a checkbox list (which is generated dynamically) and when selected the item should get added to the form values. Example: I want to display a registration form for a thing where the possible extras come from the thing that you can register for and should determine the checkbox items that are rendered and the extra get's associated to selected-extra attribute on the thing. I have created an indirect relation (:thing/selected-extras -> :selected-extra/extra -> :extra/id). This could be simplified but directly linking from selected-extras to the extra but I think the indirection has the advantage that the selected extra can be extended.

tony.kay18:11:00

I don’t have time at the moment for all of those questions, but to start: with the new multimethod rendering, subforms start at the ref attribute that takes you to them. This is where “wrapping” like table goes. YOUR defmethod is completely in control of what gets rendered…you can choose to call/not call ANY/NONE of the other multimethods…meaning you can render whatever the heck you want on that ref. They are simply there for convenience if you find them reusable in your scenario. Next: The query for data is completely determined by the fo id/attributes/query-inclusion. If you need something “extra” add it to one of those, but realize that “query-inclusion” only gets used on loads (which create does not do) and for local UI props. If you need custom initialization, then you will need to set the fo/machine option and define (usually just tweak) the state machine.

tony.kay18:11:21

The demo does define defmethod for using the “default” SUI rendering. I’m not sure what you’re looking for in terms of “how to imitate the autogenerated”…that was an older way of doing things that does NOT use the multimethods. So, you can peruse the code of the SUI plugin itself to see the different things that it does to render, but it doesn’t use the multimethods, so if you’re looking for that you won’t find it.

Tobias Burger10:11:11

Thank you for the detailed answer! What I am referring is section 7.3.6: I want to take over the form rendering of a specific form, not the whole default rendering. RAD Demo: So for example I want to take over the rendering of the InvoiceForm. In the invoice form there is the invoice/line-items attribute which is a to-many relation. I came up with the following code that renders the sub form(s):

(mapv
             (fn [line-item] (form/render-subform this invoice/line-items LineItemForm line-item))
             (:invoice/line-items props)) ; I guess this needs to get wrapped 
And my question is: is this the correct approach on how to render a to-many subform? I don't get any header rendered nor any action buttons (which is documented) but I cannot connect the dots how the header or the delete button is implemented by RADs auto generated forms. I suspect RAD does automatically inject some wrapper component in this case and I wonder if it is possible to reuse this wrapper component when overriding the form rendering.

tony.kay16:11:11

You have the source of the auto generated UI. No, the wrapper isn't reusable because it doesn't split those elements out... But form.cljc in the semantic UI plugin has what you're looking for. Just use the source

👍 1
tony.kay16:11:08

RAD core doesn't care too much about rendering. The sui plugin is intended as a first draft of UI, with the primary goals being escape (not tying you too much to any implementation of rendering, because that's the thing you most likely want control of). Reuse of the form fields is easy and that was my primary concern. Someone always wants a different layout.

tony.kay16:11:37

But your question is related to why I recently added the multi method support. It makes it easier for you to design elements that you deem important for reuse, especially since you can always just add new multi methods that your own rendering code uses.

Tobias Burger15:11:23

Thanks! The code in forms.cljc in the SUI library was the thing I was looking for! Yeah I am aware that I am asking a lot of the functionality of RAD and I have to find the right balance of when to use RAD over just using Fulcro. In my case I need a registration form with a few fields and subforms where I wanted to selectively take over the rendering and as RAD has this excellent support for the form management and lifecycle I wanted to re-use it for the registration form. I even reuse the standard SUI field and subform rendering most of the time, because I need the custom rendering only for a few attributes. The rest of the app uses the builtin RAD forms support in the admin section and it works like a charm and I couldn't be happier! Even the "standard" SUI layout of the registration form is used as it is the perfect fit for the admin UI. So my app is basically a RAD app with a bunch of (standard) admin forms and the one public registration form I want to customize. The multimethod support is awesome but is it suitable to overwrite a single special variant of a form?

tony.kay15:11:25

Nah, I'd just code it into that form's body

👍 1
Eric Dvorsak20:11:14

When I define a mutation in cljs with m/defmutation and clj with pco/defmutation, and have the mutation called in a cljc file with transact! I get an error from clj-kondo (correctly I guess) saying that I'm using a 1-arity instead of 2-arity for my mutation. How do you deal with that? I assume my transact call should be wrapped with a reader macro #?(:cljs ...) ?

tony.kay03:11:22

Yep. Best you can do

1