Fork me on GitHub
#fulcro
<
2023-04-30
>
Panel02:04:40

I need to build form from edn data. Load edn from server and render form with fulcro, so that the form can be adjusted live. Any examples or direction I should take ?

tony.kay02:04:58

Have you looked at how RAD itself works? All of the elements of Fulcro are dynamic in nature (queries, components, etc.). RAD has macros for generating things like forms at compile time, but everything it emits can also be done via code at runtime. So, the idea that you could send a form’s definition over the wire (save and load the details about the form) is straightforward in principle. It’s just a lot of bookkeeping.

tony.kay02:04:52

Of course there are limits unless your user can write code, but just the idea of “I want this kind of fact in my data model, with this label and such-n-such format” is pretty doable. Just reify the editable content in your database (you can use RAD proper for that, which will then give you the schema/resolvers and even a starting point for the DynamicForm editor itself.

tony.kay02:04:48

“Adjusted” is a wide open description of what the user is supposed to be able to do. If it’s purely decorative (move fields around) then that is way easier than generation of new elements of your data model.

Panel09:04:58

I have been learning and using fulcro but waited to be more confident before using rad. So maybe for this project I should start with a rad template and try to make something. My use case is quite simple, we are collecting biodiversity data, which is strongly formalised, but sometime we need to setup survey form with extra field, checkbox, drop-down… simple stuff barely any logic.

tony.kay01:05:11

So, here is an example of what you can do, at runtime, in RAD to build a dynamic form:

(form/form ::Foo
    {fo/id         account/id
     fo/attributes [account/name account/addresses]
     fo/layout     [[:account/name]
                    [:account/addresses]]
     fo/subforms   {:account/addresses {fo/ui AddressForm}}})
That map is just data. Keywords and nested maps, and the attributes themselves will either be in your declared RAD model, or you can dynamically add those as well (they are just maps, though may include lambdas). For dynamically generated “schema”, you’ll have to handle that to some extent yourself (unless you’re using a schema-less db, in which case it might be quite easy. So, you might transmit over the wire the form options map (possibly sending the attributes as keywords and looking them up in the front end model when they arrive), along with a unique form class name (keyword like ::Foo). Call that function and you’ll get a Fulcro component. You can add that to the registry:
(comp/register-component! ::Foo (form/form ...))
and now that component will work with dynamic queries in Fulcro proper (and you can look it up by name, of course). You can create a ui factory for rendering it dynamically:
(let [c (comp/regsitry-key->class ::Foo)
      ui-foo (comp/factory c {:keyfn (-> c comp/component-options (comp/get-ident {}) first)})]
  (ui-foo foo-props))
For UI routing, you’re going to need some kind of component that you can change the query on at runtime to point to the state of this new component. I don’t think there’s an easy way to hack it into dynamic routing, but you could probably put a placeholder in a dynamic router, and change that placeholder’s query to point to the form.

tony.kay01:05:37

you can use the RAD Form’s form/create!, form/edit!, routing integration, etc.

tony.kay01:05:10

Of course you don’t have to use RAD, but you’d be insane not to. There’s a lot of coding to do in order to make all that: state machines, queries, form-state integration, dynamic component generation, etc.

tony.kay01:05:39

You back-end, of course, is going to have to be adaptive on the resolvers and save-form. The save mechanism in RAD already has middleware, so it is trivial to augment that to make it “comprehend” dynamic data/schema. Resolving the attributes is going to be a little harder. If your schema is well-known, and you’re just letting people add/remove known things from a custom form, then of course that is much easier. You could also define a schema for schema, where the attributes are tuples like [keyword? string?] where the keyword is for the attribute name, and string is for a string value, and a different tuple for numbers like [keyword? double?] or something.

tony.kay01:05:51

RAD is perfectly happy to work on “blobs” of data as fields, so adding a plugin that knows how to render those kinds of tuples is fine, and making a resolver for them is also easier.