I’m trying to figure out the correct pattern for large multi-step forms in LiveView, specifically those that contain collections and nested items. I looked over the 0.19 announcement, the Fly post (Dynamic forms with LiveView Streams · Fly) about dynamic streams, and the TodoTrek demo (GitHub - chrismccord/todo_trek).
It seems they take advantage of the fact that there’s a separate form per each TODO entry, which works well in this context, but you can’t nest a form in HTML, so I’m a bit lost as to how to correctly implement this type of nested collection in the context of an existing form.
For example, I have a item creation page. Here’s a super simplified version of the form:
Title
Description (this is a rich text editor with various inputs inside of it which ultimately result in HTML output)
Photos
List of "linked items"
Create a linked item (create it in the DB and associate it with the pending item)
Add an existing linked item
Expand to show linked item
Edit linked item
Delete linked item from parent item (the one being created)
Imagine the “linked item” section being its own little interface with the ability to add/edit/link/delete, each of which would pop open a mini-form inside to do so.
Basically, the “linked item” component can be considered semantically similar to the kanban todo list in the TodoTrek demo app. But in this case, it’s part of the larger item creation form.
HTML doesn’t allow nesting forms and LiveView doesn’t support it either - if you try and nest a form, all the events of the inputs inside of the child form will just go straight to the parent form, the child form essentially gets ignored.
So I see a few options:
- Each of the inputs in the “linked items” component within the form has a manual
phx-change
andphx-target=@myself
set, essentially bypassing the parent form and doing its own thing. Cumbersome, loses some of the form conveniences of LiveView, but doable. - Break the big form down into small forms. Essentially,
form 1:
Title
Description
form 2:
Photos
"Linked items" is a stream (outside of the form concept entirely)
mini-form for each item in the "linked items", like in TodoTrek
This would work but validating/submitting/collecting all the individual forms into a single push seems potentially quite complex.
-
The entire page is a single form, with a single
phx-change
and the “linked items” is implemented using an embedded association. I’m not fully clear on if this solves the problem of allowing creating/linking/editing/deleting/rearranging in-line in the way that is shown in the TodoTrek demo, but perhaps it does. -
The “linked items” management happens in a modal, which takes it out of the flow of the parent
<form>
and enables the streams-with-subforms technique to work. This would work, but I don’t like it UI wise - I’d strongly prefer the “linked items” management to happen inline and not in a modal.
Any thoughts on the best route to go here?