Is it possible to pass a whole ecto schema with `phx-value-x`?

I want to pass a whole item as a parameter to an event handler? The use-case I want to support is having a select input with options of multiple types.

Right now I’m forced to do this. But I want to support items of different types that may have the same table-local id, or might not have an id field at all.

<%= for item <- @items do %>
        <button phx-click="select_item" phx-target={@myself} phx-value-id={item.id}>
          <%= render_slot(@option, item) %>
        </button>
<% end %>

I want to be able to support this below, but I’m getting a protocol Phoenix.HTML.Safe not implemented for %{description: "", id: 1, title: ""} of type Map. error.

<%= for item <- @items do %>
        <button phx-click="select_item" phx-target={@myself} phx-value-item={item}>
          <%= render_slot(@option, item) %>
        </button>
<% end %>

As you’ve discovered, you can only pass fairly basic data structures in as values. You have a couple of options:

  1. Generate a lookup server-side (e.g. a map) which links a simple key you can pass to phx-target... and use that in the event-handler to lookup the actual data item. The advantage of this is it minimises encoding/decoding, plus the size of the payload going back and forth to the browser.
  2. Or, encode your struct into a form that can be handled, e.g. JSON/XML/other, then decode it when it gets passed back to the event handler. An example of this is here: Want to pass data using phx-value, getting Error of protocol Phoenix.HTML.Safe not implemented for %{.....} - #10 by fazibear

I’d probably opt for 1 if your client doesn’t need to know anything about the data (i.e. you’re not envisaging writing any javascript hooks to decode the value).

1 Like

Thanks, I think I’ll do the first. Will put each item in a map with a numeric id assigned.