Optimum way of upgrading this function to LiveView .16+

I’m having trouble updating a view function to use the new heex syntax in LiveView .16 and up.

The original function looks like this:

def render_attributes(form, params) do 
  params
    |> Map.take(~w[L W H])
    |> Enum.sort_by(&primary_attr_weight/1)
    |> Enum.map(&to_measurement_input_group(&1, form))
end 

defp to_measurement_input_group({label, value}, form) do
    ~E"""
    <div class="form-group">
      <%= label form, "parameters_#{value}", label %>

      <div class="input__helper-right" data-helper-txt="in.">
        <%= dynamic_number_input form,
                  label,
                  value: value,
                  step: 1,
                  name: input_name(form, :parameters) <> "[#{label}]",
                  class: "input-border"
        %>
      </div>
    </div>
    """
  end

From what I understand sigil_E is deprecated in favour of sigil_H so I’d like to update this function, but just changing to sigil_H (and adding an assigns map) produces this error:

an exception was raised:
    ** (ArgumentError) lists in Phoenix.HTML and templates may only contain integers representing bytes, binaries or other lists, got invalid entry: %Phoenix.LiveView.Rendered{dynamic: #Function<11.66582273/1 in AdminWeb.CustomerView.to_measurement_input_group/2>, fingerprint: 167351826841974829345229029431399485562, root: true, static: ["<div class=\"form-group\">\n  ", "\n\n  <div class=\"input__helper-right\" data-helper-txt=\"in.\">\n    ", "\n  </div>\n</div>"]}

Technically I suppose I don’t HAVE to update the function right now, sigil_E still works but after these updates and moving forward I’d like to know how to map over an enum and generate some HTML for each value.


I know I can do:

  |> Phoenix.HTML.Safe.to_iodata()
        |> List.to_string()

or something like

~H"""
...
"""
 |> Map.get(:static)
 |> Enum.reduce("", fn x, acc -> acc <> x end)

But both of these feel like work arounds/hacks. I’d be willing to change the original function as well if there was a way to get it to fit more of an heex pattern…

Try making both those functions function components that take an assigns map and, if necessary, use assign internally to update the assigns. Actually, it would probably end up being one component. And use the for comprehension to render the list of components.

This solution worked really well in this case but is this what I should I be doing for any instance where HTML needs to be a string? I guess I would revert to my first idea?

  |> Phoenix.HTML.Safe.to_iodata()
  |> List.to_string()

This would be applicable for view tests, to match a string to a rendered/returned block of HTML. We also have a few specific use cases where our HTML has to be rendered to a string so we can parse some shortcodes in a user defined template.