OK, this is my first question on the forum, so I hope I’m able to properly spell out the situation I’m running into.
Since Liveview 0.20.4 I am having issues manually triggering a form’s submit action. Specifically the issue is that the action is triggering before the form is updated with new values.
My code was working before that release. So I’m not sure if this is a bug or I’m just doing something silly.
NOTE: I was able to hack a “solution” that demonstrates the issue by just doing an async delay on setting trigger_submit (this is not meant as a production ready solution, but rather it illustrates that delaying the submit somehow does allow for the form’s HTML to update).
Here is a redacted version (for simplicity) of the code in which the keys: user_id, vehicle and status arrive as empty strings on my POST controller.
def render(assigns) do
~H"""
<.simple_form
for={@form}
id="form"
phx-trigger-action={@trigger_submit}
action={~p"/vehicle?_action=insert"}
method="post"
>
<!-- Form inputs - general -->
<input type="hidden" name={@form[:user_id].name} value={@form[:user_id].value} />
<input type="hidden" name={@form[:vehicle].name} value={@form[:vehicle].value} />
<input type="hidden" name={@form[:status].name} value={@form[:status].value} />
</.simple_form>
"""
@doc """
The submit chain of events is triggered by a user input on a live_component which calls this event.
"""
def handle_info({:updated_inputs, {:time_zone_inputs, :checkout, component_inputs}}, socket) do
current_params = socket.assigns.form.params
updated_params = merge_state(component_inputs, current_params)
handle_event("insert", %{"form" => updated_params}, socket)
end
def handle_event("insert", params, socket) do
{:ok, final_params} = add_param_data(params["form"], socket)
changeset = Vehicle.form_changeset(%Vehicle{}, final_params)
if changeset.valid? do
# HERE - this is the line were I've been able to locate the issue
{:noreply, socket |> assign_form(changeset) |> assign(trigger_submit: true)}
# To test my hypothesis I tried a hacky idea which does work.
# the hack is to delay the trigger_submit
# which suggests to me there is some issue with the form not identifying an update was needed on the HTML hidden inputs
# socket =
# socket
# |> assign_form(changeset)
# |> start_async(:trigger_delay, fn -> :timer.sleep(700) end)
# {:noreply, socket}
end
else
{:noreply, socket |> put_flash(:error, "Data doesn't match the submission.")}
end
end
# Handles the hack...
# defp handle_async(:trigger_delay, {:ok, :ok}, socket) do
# {:noreply, socket |> assign(trigger_submit: true)}
# end
defp add_param_data(params, socket) do
# receives a map of params (all keys are strings) and merges with data from assigns
general_params = %{
"user_id" => socket.assigns.current_user.id,
"vehicle" => socket.assigns.vehicle,
"status" => :pending,
}
{:ok, Map.merge(params, general_params)}
end
# same function that comes with Phoenix Accounts
defp assign_form(socket, %Ecto.Changeset{} = changeset) do
form = to_form(changeset, as: "form")
if changeset.valid? do
assign(socket, form: form, check_errors: false)
else
assign(socket, form: form)
end
end
I have tried to include the right amount of code to avoid overcomplicating the example and yet give a good sense of what I’m trying to accomplish and the issue I’m running into… but I also realize I may be WAY to deep into my own issue and may not realize I am lacking on detail.
Huge thanks for any help!