So here is my situation, I have a main form on a page, it manages a list of products. Each of these products is a changeset struct, and it can be added dynamically.
<%= for {product, i} <- @products do %>
<%= live_component @socket, Web.Components.ProductForm, id: i, product: product %>
<% end %>
and in the Web.Components.ProductForm live component, there are 2 forms, one to actually manage the product information, and another to search and provide an auto-completion of some kind.
<div class="column is-one-quarter">
<%= s = form_for :search, "#", [as: "search-#{@id}", phx_change: :product_search, phx_target: @myself] %>
<%= label s, :query, class: "label" %>
<%= text_input s, :query, class: "input" %>
<datalist>
<%= for {product_id, product_code} <- @search_results do %>
<option value="<%= product_id %>"><%= product_code %></option>
<% end %>
</datalist>
</form>
</div>
<div class="column">
<%= f = form_for @product, "#", [as: "product-#{@id}",phx_change: :form_change, phx_target: @myself] %>
<%= label f, :remarks, class: "label" %>
<%= text_input f, :remarks, class: "input" %>
<%= label f, :quantity, class: "label" %>
<%= number_input f, :quantity, default: 0, class: "input" %>
</form>
</div>
And in the component itself, there are these handlers:
@impl true
def handle_event("form_change", params, socket) do
IO.inspect(params, label: "FORM CHANGE")
{:noreply, socket}
end
@impl true
def handle_event("product_search", params, socket) do
IO.inspect(params, label: "SEARCH CHANGE")
{:noreply, socket}
end
So my questions:
-
When my the main form changes, I got the params value of
%{"product-0" => %{....}, with theproduct-0as the map key, which I’m assuming comes from theasparam passed into the form? But when the search form changes, the params has the value of%{"search" => %{....}}, which seems to come from the atom that are passed into theform_for/4call? Or is it derived from something else entirely that I’m missing? -
With the above setup, I’m getting an issue where when multiple
@productsare present and multiple components are rendered, only search box for the last product gets rendered. It seems to be having an issue with diffing? The issue went away if I were to useform_for String.to_atom("search-#{@id}")instead, but I don’t think it is such a good idea to generate atoms dynamically. Is there any other way to generate the forms?






















