zoedsoupe
How to properly create nested form for 1-N relations?
I followed this tutorial: Nested model forms with Phoenix LiveView · FullstackPhoenix
I have a schema called Folha, defined as:
schema "folhas" do
field :competencia, :string
belongs_to :empresa, Empresa
has_many :itens, ItensFolha
timestamps()
end
@doc false
def changeset(folha, attrs) do
folha
|> cast(attrs, [:competencia, :empresa_id])
|> validate_required([:competencia, :empresa_id])
|> parse_string(:competencia)
|> foreign_key_constraint(:empresa_id)
|> cast_assoc(:itens, required: true, with: &ItensFolha.changeset/2)
end
And the ItensFolha is defined as:
schema "itens_folha" do
field :adicional_noturno, :decimal
field :bonificacao, :decimal
field :descontos, :decimal
field :dias_faltas, :integer
field :finalizado?, :boolean, default: false
field :hora_extra, :decimal
# fields to enable nested form
field :temp_id, :string, virtual: true
field :delete, :boolean, virtual: true
belongs_to :folha, Folha
belongs_to :funcionario, Funcionario
timestamps()
end
@doc false
def changeset(itens_folha, attrs) do
itens_folha
|> cast(attrs, @fields)
|> validate_required(@required_fields)
|> foreign_key_constraint(:funcionario)
|> maybe_mark_for_deletion()
end
defp maybe_mark_for_deletion(%{data: %{id: nil}} = changeset), do: changeset
defp maybe_mark_for_deletion(changeset) do
if get_change(changeset, :delete) do
%{changeset | action: :delete}
else
changeset
end
end
On the live view side, I have the scaffold files: index.ex, show.ex, form_component.ex and it’s templates!
My Folha form is:
<h2><%= @title %></h2>
<%= f = form_for @changeset, "#",
id: "folha-form",
phx_target: @myself,
phx_change: "validate",
phx_submit: "save" %>
<%= label f, :competencia %>
<%= text_input f, :competencia %>
<%= error_tag f, :competencia %>
<%= label f, :empresa_id %>
<%= text_input f, :empresa_id %>
<%= error_tag f, :empresa_id %>
<p>Item Folha</p>
<%= inputs_for f, :itens, fn i -> %>
<%= label i, :dias_faltas %>
<%= number_input i, :dias_faltas %>
<%= error_tag i, :dias_faltas %>
<%= label i, :hora_extra %>
<%= number_input i, :hora_extra, step: "any" %>
<%= error_tag i, :hora_extra %>
<%= label i, :adicional_noturno %>
<%= number_input i, :adicional_noturno, step: "any" %>
<%= error_tag i, :adicional_noturno %>
<%= label i, :descontos %>
<%= number_input i, :descontos, step: "any" %>
<%= error_tag i, :descontos %>
<%= label i, :finalizado? %>
<%= checkbox i, :finalizado? %>
<%= error_tag i, :finalizado? %>
<%= label i, :bonificacao %>
<%= number_input i, :bonificacao, step: "any" %>
<%= error_tag i, :bonificacao %>
<%= label i, :funcionario_id %>
<%= text_input i, :funcionario_id %>
<%= error_tag i, :funcionario_id %>
<%= if is_nil(i.data.temp_id) do %>
<%= checkbox i, :delete %>
<% else %>
<%= hidden_input i, :temp_id %>
<a href="#" phx-click="remove-item" phx-value-remove="<%= i.data.temp_id %>">×</a>
<% end %>
<% end %>
<a href="#" phx-click="add-item">Add a item folha</a>
<%= submit "Save", phx_disable_with: "Saving..." %>
</form>
However, where I put the handle_event/3 “add-item” and “remove_item” clauses?
I tried to put on form_component.ex but when I clicked the button, it throws a “validate” event…
So I tried to put on index.ex, however, the socket on this live view does not have the field changeset, so I can’t to retrieve existing items. What I’m doing wrong?
I created a gist with some code: https://gist.github.com/a0e7230f312fb50fe681b984bac9b7a6
I also have all templates and live views for the ItensFolha schema, could I “embed” one form_component into another?
Most Liked
zoedsoupe
Also, my test fails as:
1) test Index saves new folha (ContsWeb.FolhaLiveTest)
test/conts_web/live/folha_live_test.exs:34
** (ArgumentError) could not find non-disabled input, select or textarea with name "folha[itens][]" within:
<input name="_csrf_token" type="hidden" value="ACJTGywjKjwjHhgWHSJNEToZXmsgfTo1Vo2yIMyef-oRSVusVAi8O1R_"/>
<input id="folha-form_competencia" name="folha[competencia]" type="text" value=""/>
<input id="folha-form_empresa_id" name="folha[empresa_id]" type="text" value=""/>
code: |> render_submit()
stacktrace:
(phoenix_live_view 0.15.4) lib/phoenix_live_view/test/live_view_test.ex:885: Phoenix.LiveViewTest.call/2
test/conts_web/live/folha_live_test.exs:52: (test)
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








