How to add divs when using helper functions?

I’m using José Valim’s blog post (http://blog.plataformatec.com.br/2016/09/dynamic-forms-with-phoenix/) to structure my templates. I really like this. My template is super clean now. However, I do have a need to have a bit more control over the UI and I’m confused by how I’d generate divs with this approach.

Specifically, I have a date/time and I’m using bootstrap 4 for styling. For this form I’d like to have the input fields fall below the label. This works fine for everything but date/time which insists of 1) going to the same line; 2) being way too close to the label. What I do with just template code is:

  <div class="form-group">
    <%= form_label f, :end_time %>
    <div>
      <%= datetime_select f, :end_time, class: "form-control", id: "post_mortem_end_time" %>
      <%= error_tag f, :end_time %>
    </div>
  </div>

My current input function is:

  def input(form, field, opts \\ []) do
    type = opts[:using] || Phoenix.HTML.Form.input_type(form, field)

    wrapper_opts = [class: "form-group"]

    input_opts =
      [
        class: "form-control",
        placeholder: form_humanize(field)
      ]
      |> concat_template_input_opts(opts[:input_opts])

    validations = Phoenix.HTML.Form.input_validations(form, field)
    input_opts = Keyword.merge(validations, input_opts)

    content_tag :div, wrapper_opts do
      label = form_label(form, field, opts)
      input = apply(Phoenix.HTML.Form, type, [form, field, input_opts])

      error = AutopsyWeb.ErrorHelpers.error_tag(form, field)
      [label, input, error || ""]
    end
  end

Maybe something like

    content_tag :div, wrapper_opts do
      label = form_label(form, field, opts)
      
      inner_div = content_tag :div do
        # is apply necessary here?
        # can it be Phoenix.HTML.Form.type(form, field, input_opts)?
        input = apply(Phoenix.HTML.Form, type, [form, field, input_opts])
        error = AutopsyWeb.ErrorHelpers.error_tag(form, field)
        [input, error || ""] # I think nil is replaced with [] automatically in phoenix_html
        # so it can be [input, error]
      end
      
      [label, inner_div]
    end

could work?

2 Likes

I keep finding things are easier than I thought. I just get nervous with web UI stuff since its new for me. I broke the input into its own function with

  defp build_input(form, field, type, input_opts) do
    content_tag :div do
      apply(Phoenix.HTML.Form, type, [form, field, input_opts])
    end
  end

and that seems to work fine!