Implementing Multiple Submit Buttons with LiveView

A side view of a pair of hands typing on a laptop, with another monitor in the background

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.

Newsletter

Stay in the Know

Get the latest news and insights on Elixir, Phoenix, machine learning, product strategy, and more—delivered straight to your inbox.

Narwin holding a press release sheet while opening the DockYard brand kit box