mitkins

mitkins

I’m currently re-writing my form to create/edit Log entries with Phoenix Live View. I have an unorthodox UI - it has 2 submit buttons. 1 for “Work” and one for “Break” - offering the user the choice, but allowing the user to submit the form at the same time. So at the time of submitting the form - I need to know which button the user pressed.

In a traditional POST I use the name of the button - in my template I have the following:

<%= submit "Work", name: "work" %>
<%= submit "Break", name: "break" %>

If the user clicks a button, either work or break would exist in the list of params.

In a Live View, I don’t have this technique at my disposal. handle_event does not include the name of the submit button that was pressed.

I tried adding a phx-value-work attribute (which seems like an awesome way to solve this), but that only works with phx-click.

Does anybody have any suggestions?

Showing Posts 1 to 10

mitkins

mitkins OP

I’m thinking at this stage that I may be better off creating some client-side javascript to set a hidden field before the form is POSTed. I might have a look at the JS interop mechanism and see what’s possible there…

mindok

mindok

Does this thread help? It sounds like a similar situation.

mitkins

mitkins OP

It does. Looks like I do need to set a hidden field using javascript before phx-submit event is fired.

Though, I think I might start by adding a phx-click first:

<%= submit "Work", name: "work", "phx-click": :set_work %>
<%= submit "Break", name: "break", "phx-click": :set_break %>

In my code I have something similar to this;

  def handle_event("set_work", _params, socket), do: { :noreply, assign( socket, :work, true) }
  def handle_event("set_break", _params, socket), do: { :noreply, assign( socket, :work, false) }

  def handle_event("save", params, socket) do
     # Do database operation here
  end

I’m assuming this results in 2 round trips (phx-click followed by phx-submit), but the code is easier to read. I might do this for now until I’ve fleshed out my form

snewcomer

snewcomer

Phoenix Core Team

If we aren’t passing more information to handle_event and it helps your case, I think we should! It is so common to include two buttons in a form so something like this should be simple to handle.

Would you mind opening an issue in the LiveView repo so we can discuss?

technicalcapt

technicalcapt

In case of anyone come across this topic. Here is my solution for this particular issue.
Form

<form>
   <! -- We don't need hidden_input here. -->
  <button type="submit" id="foo-btn" phx-hook="HandleSubmitForm" name="foo" phx-hook="SetButtonState">Save</button>
  <button type="submit" id="baz-btn" phx-hook="HandleSubmitForm" name="baz" phx-hook="SetButtonState">Save and Close</button>
</form>

Js logic with jquery

// Your phx-hook logic.
// Instead of common way of submitting form, we're handling form submission with ajax.
$(this.el).on('click', '#buttonID', function(evt) {
  evt.preventDefault()
  let targetButton = evt.target.getAttribute("name")
  let form = document.getElementById("yourFormID")
  const formData = new FormData(form)
  formData.append("button", targetButton) # pattern match on this on server side.

  $.ajax({
    url: "/broadcast", # Route for your controller.
    type: "PUT", # PUT or POST
    data: formData,
    processData: false,
    contentType: false,
    headers: {
      X_CSRF_TOKEN: yourCsrfToken
    }
  })
  .done((resp) => {
    # Do something with resp
  })
  .fail((err) => {
    # Do something with err
  })
});

Use a controller to handle ajax request.

# And then in your broadcast controller.
  def send(conn, params) do
   data = params # Handling data from the form.
    Phoenix.PubSub.broadcast( # Broadcast updates to LiveView
      YourApp.PubSub,
      broadcast_topic,
      {:update_content, %{data: data}}
    )

    send_resp(conn, 200, "ok") # Send some response or err
  end
# Dont forget to subscribe topic in your mounted LiveView
def mounted(_params, _session, socket) do
  Phoenix.PubSub.subscribe(YourApp.PubSub, broadcast_topic)
...

And finally handle_info/2

  def handle_info({:update_content, %{data: data}}, socket) do
    # Do something with updated data
    {:noreply, socket}
  end
marcofiset

marcofiset

Isn’t this kind of convoluted?

This issue can be solved purely on the client side with javascript, which you’re already doing. Instead of initiating an ajax call, why not simply set a hidden input on the form?

APB9785

APB9785

Creator of ECSx

My first intuition here would be to use phx-click instead, and pull the form data out of the assigns manually (assuming you’re using live validation).

ouven

ouven

I tried this but the validation didn’t work, because, if the form was not submitted, the class “phx-no-feedback” is set to the fields, that had no focus yet. So the changeset errors are not shown.

nihil2501

nihil2501

Here is a formulation that relies on

  • SubmitEvent.submitter docs
  • The useCapture option of addEventListener docs (maybe ensuring the behavior occurs before the actual submit occurs?)
<.form
  :let={f}
  for={:form}
  phx-target={@myself}
  phx-hook="MultiSubmitForm"
  id="user-form"
>
  <%= submit "Alternate Save", "phx-submit": "alternate_save_user" %>
  <%= submit "Save", "phx-submit": "save_user" %>
</.form>
Hooks.MultiSubmitForm = {
  mounted() {
    this.el.addEventListener("submit", (event) => {
      let phxEvent = event.submitter.getAttribute("phx-submit");
      event.target.setAttribute("phx-submit", phxEvent);
    }, true);
  }
}

It worked locally for me in a really simple example, but I’m both new to Elixir and Phoenix and not intimately familiar with browser behavior, so it might be inaccurate.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
itzmidinesh
Hi all, I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
pragdave
How do I tell Hologram not to escape HTML when substituting into templates? {Textile.render(@product.long_description)} escapes the HTM...
New
rlipscombe
I’d like to create a file with 600 permissions (rw-------), but there’s a race condition if I create it and then change the permissions. ...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
rlipscombe
When I use Mix.install with a git dependency, using git@github.com:... how do I change the SSH identity used? I’ve got two Github accoun...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews