Hi,
There are quite a few issues that describes the current situation when you want to distinguish which button was pressed to submit a form with liveview.
opened 02:10PM - 16 Apr 19 UTC
closed 02:34PM - 25 Apr 19 UTC
<!--
*Note:* Currently Live View is under active development and we are focused… on getting a stable and solid initial version out. For this reason, we will be accepting only bug reports in the issues tracker for now. We will open the issues tracker for features after the current milestone is ironed out.
And remember – be nice and have fun!
-->
### Environment
* Elixir version (elixir -v): Elixir 1.8.1 (compiled with Erlang/OTP 20)
* Phoenix version (mix deps):
* phoenix 1.4.3 (ref [06e60fe](https://github.com/phoenixframework/phoenix/commit/06e60fe17503cec168928c6fea4df25b9f129559))
* phoenix_html 2.13.2 (ref [2208553](https://github.com/phoenixframework/phoenix_html/commit/22085530f23322d360ddf8944f08d468c836f1b1))
* phoenix_live_view 0.1.0 (ref c7ea73b)
* NodeJS version (node -v): v11.11.0
* NPM version (npm -v): 6.7.0
* Operating system: MacOS 10.14 (Mojave)
### Actual behavior
In an app I'm working on, I have a form that has two different submit buttons:
```
<%= submit "Do Thing A", name: "thing_to_do", value: "a" %>
<%= submit "Do Thing B"", name: "thing_to_do", value: "b" %>
```
This submits to a normal controller, and the params tell me which button was clicked:
```
"thing_to_do" => "a"
```
I also have a `phx_submit` form with two buttons:
```
<%= submit "Save", name: "submit_type", value: "save" %>
<%= submit "Delete", name: "submit_type", value: "delete" %>
```
When I click one of these, the params I get in my live view do not tell me which button was clicked; there is no `"submit_type"` param.
### Expected behavior
I expected the params given to the live view's `handle_event` to include the button value.
opened 11:09PM - 01 Dec 19 UTC
closed 01:42PM - 09 Dec 19 UTC
wontfix
<!--
*Note:* Currently Live View is under active development and we are focused… on getting a stable and solid initial version out. For this reason, we will be accepting only bug reports in the issues tracker for now. We will open the issues tracker for features after the current milestone is ironed out.
And remember – be nice and have fun!
-->
### Environment
* Elixir version (elixir -v): Elixir 1.8.1 (compiled with Erlang/OTP 20)
* Phoenix version (mix deps): 1.4.11
* Phoenix LiveView version (mix deps): 0.4.1
* NodeJS version (node -v): v8.11.3
* NPM version (npm -v): 6.12.0
* Operating system: Win 10 Pro 1803
### Actual behavior
<!--
Describe the actual behaviour. If you are seeing an error, include the full message and stacktrace. If you can provide a link to sample app that reproduces the behaviour, even better!
-->
I have a form that I use to create/edit logs. Here's a cut down version of the schema:
``` elixir
schema "captains_log" do
field :comment, :string
field :work, :boolean, default: false
belongs_to :user, Zoinks.Accounts.User
timestamps()
end
```
I already have a version of the app that uses a traditional POST:
``` elixir
<%= form_for @changeset, @action, fn f -> %>
<%= textarea(f, :comment) %>
<%= submit "Work", name: "work" %>
<%= submit "Break", name: "break" %>
<% end %>
```
In my `LogController`, I have an `:update` method that uses the following technique to determine which button was pressed:
``` elixir
def update(conn, %{"log" => log_params } = params) do
is_work = Map.has_key?( params, "work" )
log_params = Map.put( log_params, "work", is_work )
# Do stuff with log_params
end
```
Now I'm trying to support the two button UI with Live View. So I've set the event handler for the form:
``` elixir
<%= form_for @changeset, @action, [phx_submit: :save], fn f -> %>
```
And here's what's currently in my event handler:
``` elixir
def handle_event("save", %{"log" => log_params} = params, socket) do
IO.inspect params
{ :noreply, socket }
end
```
When I look at the console, I can see that Live View does not include the name/id of the button that triggered the event. There is no convenient way to find out this information.
### Expected behavior
Well, I wasn't expecting it to work. But I was _hoping_ 😬 that there might be a simple trick that I could implement. This issue was also raised in https://github.com/phoenixframework/phoenix_live_view/issues/184. I assume the best way forward with the current version is to write a little bit of javascript that will set a hidden field in the form (before the event is triggered)
It would be nice if Live View somehow captured this information and passed it up as a param for the `phx-submit` event. Then I wouldn't have to implement anything. Doing so would mean that I could fall back to my POST/LogController code when javascript isn't enabled 😸
opened 03:54PM - 03 Sep 20 UTC
closed 12:12PM - 05 Sep 20 UTC
### Environment
* Elixir version (elixir -v):
```
Erlang/OTP 23 [erts-11.… 0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Elixir 1.10.3 (compiled with Erlang/OTP 22)
```
* Phoenix version (mix deps): 1.5.4
* Phoenix LiveView version (mix deps): 0.14.4
* NodeJS version (node -v): 12.13.0
* NPM version (npm -v): 6.14.8
* Operating system: macOS
* Browsers you attempted to reproduce this bug on (the more the merrier): Firefox
* Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: Yes
### Actual behavior
When I have a form like the following with multiple submit buttons (in my app it's more complex than this, simplified it for understanding my issue).
```eex
<%= f = form_for @changeset, Routes.form_path(@socket, :update), [phx_submit: :submit] %>
<button name="action" type="submit" value="add">Add</button>
<button name="action" type="submit" value="remove">Remove</button>
<button type="submit">Save</button>
</form>
```
Whenever I press one of the "action" buttons, I never get the action value passed to the event handler in LiveView. With a normal HTTP form and Phoenix, this works as expected.
### Expected behavior
I expect the correct action value to be passed to my event handler in LiveView.
Why did I ran into this issue? I have a form where an user can add and remove groups of input elements. But when I remove or add a group through `phx-click`, the other groups input values get cleared. So I figured that if I use submit buttons with an action value, I also have the form state so upon rerendering, the changeset contains all the correct values to recreate the input elements.
Here is my new hack to tackle this problem using current liveview implementation (0.17.5).
I’ve added this function to my app.js to properly factorize the code (but this is not mandatory, it could be put into the template file as well)
// webapp.submit submits the form form_id using event bypassing liveview phx-submit default
// ----------------------------------------------------------------------------------------
webapp.submit = (form_id, event) =>
webapp.live_socket.execJS(document.getElementById(form_id),
`[["push", {"event": "${event}"}]]`, 'submit')
note: webapp is my toplevel object in which I also stored the liveSocket
Then in the template you can simply create your buttons like here (extract from a modal template)
<section class="modal-card-body thin_scroll">
<.form let={f} for={@changeset} id="form_modal" phx-submit="save_goal" as="goal">
... your form content ....
</.form>
</section>
<footer class="modal-card-foot">
<button class="button is-primary" onclick="webapp.submit('form_modal', 'save_decision')"><%= gettext("Decision") %></button>
<button class="button is-primary" onclick="webapp.submit('form_modal', 'save_information')"><%= gettext("Information") %></button>
<button class="button is-primary" form="form_modal" type="submit"><%= gettext("Validate") %></button>
</footer>
Here I have kept a traditionnal submit button in third position that will trigger the default phx-submit event.
Finally, you only have to pattern match to get the wanted behaviour in you .ex file
def handle_event("save_decision", params, socket),
do: handle_event("save_goal", Map.put(params, "type", "decision"), socket)
def handle_event("save_information", params, socket),
do: handle_event("save_goal", Map.put(params, "type", "Information"), socket)
def handle_event("save_goal", params, %{assigns: assigns} = socket) do
Logger.info("params: #{inspect(params)}")
...
{:noreply, socket}
end
And that’s it !
Cheers,
Sébastien