How do I output JSON in a *.html.heex template? How do I get around Phoenix.HTML.Safe?

I have a template file that looks like the following:

<h1> The title: <%= @title  %> </h1>
<%= Jason.encode(@my_data) %>

But Phoenix is complaining, saying

protocol Phoenix.HTML.Safe not implemented for {:ok, "[{\"properties\":{\"gridProperties\":{\"etc

Apparently I can’t just output a JSON string of data into my html template?

How can I tell Phoenix that this data is safe to encode as JSON and display?

Just from the error message, it sounds like you’re passing the tuple {:ok, string} and perhaps you need to just pass the string.

I haven’t tested or really familiar but looks like the inputs it has a protocol for are here in the docs.

Then it’ll return either the {:ok, String.t()} or the error tuple.

Edit

I realize the error message is cause you’re passing the :ok tuple to the template rather than a string.

Ah I think you might want to use a helper function or similar so you can clean the return you’re getting to be the string you want to stick in there.

You could even just write <%= to_string(Jason.encode(@mydata)) %> if you want to show the tuple.

Not totally sure what you’re asking, again, but if you want to render the json inside your html then you might want to check out how livebook approaches rendering different outputs inside the “cell” of the html page to draw inspiration.

1 Like

Maybe like this?

<pre><%= Jason.encode!(@my_data) %></pre>

Note the exclamation mark.

1 Like

I just quickly tested this with @kokolegorille’s suggestion for Jason.encode!/2:

<%= Jason.encode!(%{a: 1}) %> and it outputs the tuple straight into the HTML as a string.

Jason.encode/2 throws the protocol undefined error. My to_string/1 suggestion doesn’t work for the similar reason: Jason.encode/1 returns the {:ok, String.t()} tuple whereas Jason.encode!/2 returns the String.t().

So, you would need to use Jason.encode!/2 or more specifically <%= Jason.encode!(@my_data) %> as koko suggests and it should work just fine.

2 Likes