Assign state to LiveComponent once using update/2

Hello everyone!

We have a complex form in our application that is generated based on user configuration. The form consists of a LiveComponent that handles validation and saving, and several LiveComponents that represent the form elements (e.g. input field or select). The form elements must be LiveComponents because they need to handle their own events. For example, we have a multi select with search capabilities. We just refactored the form elements to LiveComponents because handling all the events in one LiveComponent was a mess and too complex. Especially when there were multiple complex form elements of the same type. But having the form elements as LiveComponents brings another problem. These form elements / LiveComponents are now updated every time another form element changes. This is because changing any form element triggers form validation. This results in changes to the form, and because each form element depends on the form, they are all updated.

The result is that the state of each form element is reset to its initial state (for example, the search term in our multi select will be lost and reset). This is because we assign everything in the LiveComponents update/2 function. We cannot use mount/1 because in this function we do not have all the information we need to render the form element properly (e.g. the assigns given to the LiveComponent).

Is there a way to assign state to a LiveComponent only once, using only update/2?

Thanks in advance!

Do you pass in the complete @form for each of those LiveComponents? Or just the part you need (e.g. @form[:some_field]? I could imagine the latter has better change tracking.
And you’re doing the new to_form/2, right?

update doesn’t cause you to lose state, it just gets called multiple times. If you look at socket.assigns in update/2 and there are already values that you want, then don’t overwrite them.

1 Like