Recently, on a client project I faced a common issue with web forms: having several submit buttons in one form with different actions. This is quite common: save as draft or publish in blog engines, comment vs. comment and close in Github issues, etc. But this time was the first time I faced it using Phoenix LiveView.
When I started looking into the issue there were several search results, all with convoluted fixes, e.g. using JavaScript to set a hidden input, having several forms and relying on phx-change to get the right data in the server, etc. Everything looked too complicated for such a simple task. In HTML you can define formaction in the submit button to override the action in the parent form.
Luckily, in Phoenix LiveView 0.18.17 support for this feature was added and now we can easily do this by using the name and value attributes of each button. Let’s take a look at a simple example: a minimalistic blog post editor.
Let’s assume we have a simple form in Phoenix LiveView with the following template:
<div>
<.form for={@changeset} :let={f} phx-submit="save" phx-target={@myself}>
<%= text_input f, :title %>
<%= textarea f, :body %>
<%= submit "Save as draft", name: "save", value: "draft" %>
<%= submit "Publish", name: "save", value: "publish" %>
</.form>
</div>
Then, in our component we can have the following handle_event:
defmodule MyAppWeb.PostForm do
use MyAppWeb, :live_component
def handle_event("save", %{"save" => save_type, "post" => post_params}, socket) do
socket =
case persist(save_type, socket.assigns.changeset, post_params) do
{:ok, _post} ->
# On success
socket
{:error, changeset} ->
assign(socket, :changeset, changeset)
end
{:noreply, socket}
end
def persist("draft", changeset, params) do
# Save as draft
end
def persist("publish", changeset, params) do
# Publish
end
end
Or pattern-match directly on the handle_event
or handle it in whatever form we want.
You can see that the params now contain a key with the value of the name of the button whose value is coming from the value attribute.
In this case, we have <button name="save" value="draft">Save as draft</button>
adding "save" => "draft"
to the params.
Conclusion
In this blog, we learned how to handle multiple submit buttons on a single form using LiveView. Now you can implement this on your own pages without leaving the comfort of Phoenix LiveView!
Ready to get started with the best Elixir has to offer? Contact us today to learn how we can put it to work for you.