#LiveView forms and changesets

9 messages · Page 1 of 1 (latest)

runic hare
#

Massive thanks in advance if anyone can help me!

In my def mount I create my changeset with a foreign key already in there. From printing out the changeset I can see it creates it as expected

#Ecto.Changeset<
  action: nil,
  changes: %{message_header_id: 1}, # THIS BIT
  errors: [],
  data: #DEMO.Messages<>,
  valid?: true
>

But soon as my def handle_event("validate", %{"messages" => user_params}, socket) do runs it immediately gets wiped. I assume it's because I have no form entry for the foreign key in my live view form - is there a way I can get around this?

Form example:

<.form let={f} for={@changeset} phx-change="validate" phx-submit="save">
    <%= label f, :message %>
    <%= text_input f, :message, phx_debounce: "blur" %>
    <%= error_tag f, :message %>
   
    <div>
        <%= submit "Save", phx_disable_with: "Saving..." %>
    </div>
</.form>

Validate function:

  def handle_event("validate", %{"messages" => user_params}, socket) do
    changeset =
      %Messages{}
      |> Messages.changeset(user_params)
      |> Map.put(:action, :insert)

    IO.inspect(changeset)

    {:noreply, assign(socket, changeset: changeset)}
  end
# OUTPUT:
#Ecto.Changeset<
  action: nil,
  changes: %{message: "test"}, # message_header_id IS GONE
  errors: [],
  data: #DEMO.Messages<>,
  valid?: true
>
delicate cedar
#

"I can see it creates it as expected", what do you mean creates? This changeset that you show initially hasn't been actioned (it's nil)

#

you just mean the changeset is assigned initially in mount?

runic hare
# delicate cedar you just mean the changeset is assigned initially in mount?

Yes sorry, I meant that the changeset is made with the 'message_header_id: val' in the changes, meaning my my cast is correct so I know it's not getting deleted at that point

  def changeset(user, attrs) do
    user
    |> cast(attrs, [:message, :message_header_id])
    |> foreign_key_constraint(:message_header_id)
    |> IO.inspect()
  end
unreal viper
#

there are several ways you could approach this, but I think I'd recommend adding the inputs like you suspected. Use inputs_for and a hidden input to hold the ID so that when you submit it's part of the params

#
<%= for fp <- inputs_for(f, :friends) do %>
  <%= hidden_inputs_for(fp) %>
  <%= text_input fp, :name %>
<% end %>
runic hare
#

thank you!!!!! will give a go!

unreal viper
#

another approach is this:

changeset =
  existing_changeset
  |> Messages.changeset(user_params)
  |> Map.put(:action, :insert)

i.e. don't put a brand new %Message{} into the changeset struct, put the existing changeset that you previously created in mount