Submit Form with buttons and values (Issue 184)

I use Live View in one of my projects, but i struggle when it comes to
forms with two buttons with names and values. I need them to decide on
the serverside, if want to add or remove an entry.

I found this [https://github.com/phoenixframework/phoenix_live_view/issues/184](http://Issue 184),
which describes the same issue, but i can’t retrace the hack, which is described there.

Please, can somebode gives me an example?

Try using a div styled as a button rather than a button. e.g.

<div phx-click="add_thing" phx-value-thing-id="..." class="btn btn-secondary">Add New</div>
<div phx-click="remove_thing" phx-value-thing-id="..."  class="btn btn-warning">Delete</div>

I was stumped on this last week… any button within a form seems to fire the submit handler event for the form.

1 Like

Please don‘t do that. The correct solution is using a button with type="button". The default type of a button is submit, which will submit the form it‘s part of.

12 Likes

This would not work on apple devices. Especially iPhones and iPads. The correct way would be to use

<button type="button">

as pointed out by @LostKobrakai

Ok - thanks all. Time to fix a bit of code :slight_smile:

Edit: done - this works as expected in a similar situation to @UlfAnger… Apologies if I led you astray

<button type="button" phx-click="add_thing" phx-value-thing-id="..." class="btn btn-secondary">Add New</button>
<button type="button" phx-click="remove_thing" phx-value-thing-id="..."  class="btn btn-warning">Delete</button >

Sorry, but I don’t get it. Perhaps, i described my problem wrong.

Here is a small form :

<form phx-submit="request_to_booking">
        <div class="card">
            <div class="card-header bg-danger">Anfragen</div>
            <select name="request" class="custom-select">
                <option value="51">Miles, John</option>
                <option value="52">Miller, Bob</option>
            </select>
            <div class="card-footer">
                <div class="btn-group" role="group">    
                    <button class="btn btn-success btn-sm" name="button" type="submit" value="adding">Hinzufügen</button>                    
                    <button class="btn btn-danger btn-sm" name="button" type="submit" value="refuse">Ablehnen</button>        
                </div>
            </div>
        </div>
    </form>

The use case is pretty easy. I have a select box where I can select an item and than the user decides if the entry will be added to refused. That’s all.

As you can see, if I press the submit button the form with the selected user will be send to the handle_event function with “request_to_booking” and the id of the requester.

If I would do this:

<div phx-click="add_thing" phx-value-thing-id="..." class="btn btn-secondary">Add New</div>

Now i have a click button and a phx-value. Which value is set here and how? Also, how can is submit my form now?

There’s nothing really special about form submission in a liveview. It’s just a websocket payload getting delivered to an event handler, exactly the same as any communication from the browser to the liveview. The only two minor differences are:

  1. it is automatically wired up to any submit button associated with the form, and
  2. the form parameters are passed into the handler. The mechanics of handling the event, redirecting etc are the same for any event.

So the main issue you have to deal with is not having the form parameters passed into the event handler for another button (in this case handle_event("add_thing", ..., socket)

If you already have a form change handler (e.g. phx-change="validate" - quite common if you have live validation), then you have the changeset to do what you would do on form submit, held in socket.assigns already.

If you don’t, and you don’t want one, your phx-value-xxx will need to contain some identifier that you can use to recreate what you need in the event handler.

This is actually the problem described in the issue you linked in the initial post. The problem is that only a native form submit (with page load) will include the value of the clicked submit button/input. As soon as you prevent the native handling to submit the form using javascript/formdata this won‘t happen, because it‘s no longer aware of which button was clicked. You‘d need to work around that with even more js, to e.g. fill a hidden field with the value of the submit button when it‘s clicked, so later the formdata obj. does include the value of the hidden field.

Thanks for your help, now I got it.

Here is my solution :

<form phx-change="selection_changed_requester">
        <div class="card">
            <div class="card-header bg-danger">Anfragen</div>
            <select name="request" class="custom-select">
                <option selected=""></option>
                <option value="53">Angermann, Ulf</option>
            </select>
            <div class="card-footer">
                <div class="btn-group" role="group">    
                    <div phx-click="add_requester" phx-value-requester-id="" class="btn btn-sm btn-success btn-block">Hinzufügen</div>                    
                    <div phx-click="delete_requester" phx-value-requester-id="" class="btn btn-sm btn-danger">Ablehnen</div>                                        
                </div>
            </div>
        </div>
    </form>

I had to add a phx_change handler to the form, which sends the field request to the handle_event function, which writes a field request-id in the socket. This field will be inserted into the phi-value-requester-id variable. Now, if you click on the one the two buttons, the value requester-id can be handled in one of the functions add_requester or delete-requester.

2 Likes

Good to hear you have it going. As a possible refinement, you already have the id value in socket.assigns so you probably don’t need the phx-value-requester-Id in your template either - just ignore the event params and look the id up from socket.assigns.