Search code examples
elixirecto

Specify ordering of nested Phoenix form fields


I'm setting up a form with nested fields, how do I specify the order of the fields so they're not grouped together.

I can use inputs_for to display the nested fields, however it displays them all at once. I want to display them in a dynamic order.

For example:

<%= inputs_for f, :apples, fn fa -> %>
  <%= label fa, :name %>
  <%= text_input fa, :name %>
  <%= error_tag fa, :name %>
<% end %>

<%= inputs_for f, :oranges, fn fo -> %>
  <%= label fo, :name %>
  <%= text_input fo, :name %>
  <%= error_tag fo, :name %>
<% end %>

This will group all the apples and oranges fields together for each nested association. So for 2 apples and 3 oranges it will show:

-apple

-apple

-orange

-orange

-orange

What I want is to display them something like:

-apples

-oranges

-apples

-oranges

-oranges


Solution

  • You can access the data in from, it is in form variable passed into the callback function in form_for/4. So you can create a function that takes in that form, sorts and combines your apples and oranges, then renders them with your ordering.

    <%= form_for @settings, Routes.config_path(@conn, :save), fn f -> %>
        <%= render_apples_and_oranges(f) %>
    <% end %>
    

    Then in your view file define function render_apples_and_oranges\1

      def apples_and_oranges(%{data: %{apples: apples, oranges: oranges}} = form) do
        # Sort and combine apples and oranges
        render("apples_oranges_field_template.html", form: form, apples_and_oranges: sorted_apples_and_oranges)
      end
    

    And then create new template for rendering the apples and oranges:

    <%= for field <- @fields do %>
        <%= text_input(@form, field.name, value: field.value %>
    <% end %>