Phoenix LiveView how to add more values to session when form is submitted?

I am trying to add the extra key-value pair "list_id" => @list.id in addition to what the form sends by default to the session that will be passed into def handle_event("save", session, socket). How can I accomplish this?

I have tried using JS.push in phx-submit, but that has no effect.

list_live.html.heex:

def handle_event("save", session, socket) do
    #
end

form.html.heex:

<%#  form.html.heex %>

<.form
  let={f}
  for={@changeset}
  phx-change="validate"
  phx-submit={Phoenix.LiveView.JS.push("save", value: %{"list_id" => @list.id})}
  phx-value-list_id="1"
>
  <%= if @changeset.action do %>
    <div class="alert alert-danger">
      <p>
        Oops, something went wrong!
      </p>
    </div>
  <% end %>

  <%= label(f, :content) %>
  <%= text_input(f, :content) %>
  <%= error_tag(f, :content) %>

  <button type="submit">
    Save
  </button>
</.form>

Did you mean “passed into def handle_event” ?

If so, this works:

<.form
  let={f}
  for={@changeset}
  phx-change="validate"
  phx-submit="save"
>
  <%= hidden_input f, :list_id, value: @list.id %>
</.form>
1 Like

Just out of curiosity, with that, the resulting session passed into handle_event is:

%{"list_item" => %{"content" => "", "list_id" => "42"}}

Is there a way to instead pass in a map like this upon submitting the form:

%{"list_id" => 42,"list_item" => %{"content" => ""}}

It’s not a session that is passed to handle_event, it is a params map.

You can structure the changeset any way you like really, with a schemaless changeset or an embedded changeset, but you’ll need to nest/embed that list_item.

1 Like

I have the same question as OP but I am using Phoenix LiveView v0.20.7 and hidden_input doesn’t seem to exist anymore. As an example, I would like to get the following to work:

<.form
  id="sandbox-form"
  :let={f}
  for={%{"fieldA"=>""}}
  phx-submit={JS.push("sample", value: %{ "fieldB" => "static" })}
>
  <.input field={f["fieldA"]} label="fieldA"/>
  <.button>Submit</.button>
</.form>

What I end up getting is:

handle_event("sample", %{"fieldA" => "whatever"}, #Phoenix.LiveView.Socket<>)

Is there a way to add values to the form submission in the latest version?

EDIT: I should note that I am aware that I could use phx-value-fieldB attribute but it has 2 problems.

  1. it downcases the key added to the params (fieldB → fieldb)
  2. it only allows strings

You can use <.input> to make a hidden input.

To your points:

  1. Is that such a big deal? Why do you need uppercase letters in the field names?
  2. You need to parse it anyway.

I see that I overlooked that “hidden” is a valid type for the .input template. For posterity, what cmo is alluding to is the following:

<.input type="hidden">

To your responses:

  1. This seems fairly obvious, but if you are calling a common event that is being used in many locations, you now need to either refactor all other uses or make a case to handle this specific limitation.
  2. No, you don’t. If you use the JS.push version it handles all JSON encoding/decoding between the front-end and back-end. For example, if you want the value to be an array or object you don’t have to do Jason.decode!() on the Elixir side which is much cleaner.

For added context, JS.push will merge the phx-value-* attributes (as strings) into the value option. However, when used with a form, it ignores the value option entirely but still merges the phx-value-* attributes.