Want to pass data using phx-value, getting Error of protocol Phoenix.HTML.Safe not implemented for %{.....}

I want to pass the data using the phx-value but getting Error of protocol Phoenix.HTML.Safe not implemented for %{…}. Following is my code-

phx-value="<%= @job_opening %>"

I think my error is because the data present in the job_opening is like %{.........} (Map/Struct like data).

How can I pass this data, any other way? Your response will be highly appreciable.

iex(1)> EEx.eval_string("<%= @phx_value %>", assigns: [phx_value: 1])
"1"
iex(2)> EEx.eval_string("<%= @phx_value %>", assigns: [phx_value: %{id: 2}])
** (Protocol.UndefinedError) protocol String.Chars not implemented for %{id: 2}
    (elixir) lib/string/chars.ex:3: String.Chars.impl_for!/1
    (elixir) lib/string/chars.ex:22: String.Chars.to_string/1
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
    (stdlib) erl_eval.erl:449: :erl_eval.expr/5
    (stdlib) erl_eval.erl:126: :erl_eval.exprs/5
    (elixir) lib/code.ex:590: Code.eval_quoted/3
    lib/eex.ex:224: EEx.do_eval/3
iex(2)> EEx.eval_string("<%= @phx_value.id %>", assigns: [phx_value: %{id: 2}])
"2"
iex(3)>

i.e. it is up to you to in detail specify the markup (HTML) that shows the information on the page

If you just want to quickly see the value on the page this might work:

iex(3)> EEx.eval_string("<%= inspect(@phx_value) %>", assigns: [phx_value: %{id: 3}])
"%{id: 3}"
iex(4)>

Is this… for html template?

I mean if it is, it’s really weird how you have to do it that way. It seems like a security risk.

I have no idea what you’re doing but perhaps this library may help? https://github.com/rrrene/html_sanitize_ex

I use it often enough because I’m paranoid of user input.

What do you expect as a result? HTML is just string information so you need to decide how to encode the elixir data you have into some string representation. It could be encoded in json/xml or whatever other string data format is out there.

I don’t want to show the result on the HTML page instead, I want to pass data from HTML page to .ex file.
Here is code in my live HTML template-

 phx-click="archive_stage" phx-value="<%= @job_opening %>"

and following function will be trigerred when above code is clicked, and I want to pass job_opening to below function.

def handle_event("archive_stage", job_opening, socket) do

Now, the data present inside the job_opening is cause the error - protocol Phoenix.HTML.Safe not implemented for %{…}.

And, the data inside the job_opening is schema data.

I think you’re not completely aware of how live-view works. You cannot pass data you have at the time of rendering to the socket handling the updates. Those are completely different processes, which never communicate directly which each other. The only data the socket connection receives comes from the rendered html the client received (or from messages sent to the socket, but the socket does not yet exist at the time of rendering).

The documentation suggests to me that the handle_event/3 params are used for form submissions.

Wait…

  • An optional "phx-value" binding on the clicked element

Try something like

 phx-click="archive_stage" phx-value="<%= @job_opening.id %>"
def handle_event("archive_stage", job_opening_id, socket)

i.e. only use the minimal amount of information to identify the entity - not the whole data that is the entity.

Like peerreynders mentioned, in my LiveView template, I have:

<button phx-click="approve" phx-value="<%= @request.id %>">Approve</button>

And

def handle_event("approve", value , socket) do
  id=String.to_integer(value)
  request = Requests.approve_request!(id)
  ..............
end

I should have written

def handle_event("approve", value , socket) do
  request =
           String.to_integer(value)
           |> Requests.approve_request()
  ..............
end

Since I use several times id in this function, I didn’t use |> in my code.

Hi, I’ve got the same problem, ended up with binary_to_term and base64.

Code look like this:

defmodule SomethingWeb.SomethingLive do
  use Phoenix.LiveView

  def render(assigns) do
    ~L"""
      <div phx-click="test" phx-value="<%= encode(%{value: 1, test: "..."}) %>">ClickMe</div>
    """
  end

  def handle_event("test", data, socket) do
    data = decode(data)

    # data.value => 1
    # data.test => ".."

    {:noreply, socket}
  end

  defp encode(value) do
    value
    |> :erlang.term_to_binary()
    |> Base.encode64()
  end

  defp decode(value) do
    value
    |> Base.decode64()
    |> elem(1)
    |> :erlang.binary_to_term()
  end
end

There is no point to use it! Just look here: https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#module-click-events