Working with nested associations in LiveView
Creating forms of nested associations in LiveView can be intimidating and a head-scratcher at first. It turns out it is actually very easy!
In my sports example, I have a Match
which has many PlayersInMatch
, which has many PlayersInQuarter
. We start with a changeset around match Ecto.Changeset.change(match)
with everything preloaded.
The trick is, in order to update everything in the handle_event
callback, you need to make sure that the id of all the associations is present in the form, and you do this by rendering hidden_inputs_for(assoc)
at each level.
<%= for player <- @players do %>
<%= hidden_inputs_for(player) %>
<li class=""><%= player_name(player) %></li>
<%= for piq <- inputs_for(player, :players_in_quarter) do %>
<%= hidden_inputs_for(piq) %>
<li class="border pl-2 py-1"><%= number_input piq, :points %></li>
<% end %>
</li>
<% end %>
When the callback is called, you will get all of the nested associations in the Match
. Then it is simple as
def handle_event("validate", %{"match" => params}, socket) do
changeset =
socket.assigns.match
|> Ecto.Changeset.cast(params, [])
|> Ecto.Changeset.cast_assoc(:players_in_match, with: &PlayerInMatch.update_changeset/2)
{:noreply, assign(socket, :changeset, changeset)}
end
Tweet