diff --git a/lib/ash_phoenix/form/auto.ex b/lib/ash_phoenix/form/auto.ex index 9c6bf3f..f87b866 100644 --- a/lib/ash_phoenix/form/auto.ex +++ b/lib/ash_phoenix/form/auto.ex @@ -69,7 +69,8 @@ defmodule AshPhoenix.Form.Auto do ], sparse_lists?: [ type: :boolean, - doc: "Sets all list type forms to `sparse?: true` by default.", + doc: + "Sets all list type forms to `sparse?: true` by default. Has no effect on forms derived for embedded resources.", default: false ] ] @@ -451,9 +452,9 @@ defmodule AshPhoenix.Form.Auto do [ type: type, resource: embed, - sparse?: auto_opts[:sparse_lists?], create_action: create_action.name, update_action: update_action.name, + embed?: true, data: data, forms: [], updater: fn opts -> diff --git a/lib/ash_phoenix/form/form.ex b/lib/ash_phoenix/form/form.ex index 6e26093..93ff53a 100644 --- a/lib/ash_phoenix/form/form.ex +++ b/lib/ash_phoenix/form/form.ex @@ -1260,8 +1260,12 @@ defmodule AshPhoenix.Form do """ @spec params(t()) :: map def params(form, opts \\ []) do + # These options aren't documented because they are still experimental hidden? = opts[:hidden?] || false - indexed_lists? = opts[:indexed_lists?] || false + indexer = opts[:indexer] + indexed_lists? = opts[:indexed_lists?] || not is_nil(indexer) || false + transform = opts[:transform] + only_touched? = Keyword.get(opts, :only_touched?, true) form_keys = form.form_keys @@ -1279,57 +1283,79 @@ defmodule AshPhoenix.Form do params end - form.form_keys - |> Enum.filter(fn {key, _} -> + untransformed_params = + form.form_keys + |> only_touched(form, only_touched?) + |> Enum.reduce(params, fn {key, config}, params -> + case config[:type] || :single do + :single -> + if form.forms[key] do + nested_params = + if form.forms[key] do + params(form.forms[key], opts) + else + nil + end + + if form.form_keys[key][:merge?] do + Map.merge(nested_params || %{}, params) + else + Map.put(params, to_string(config[:for] || key), nested_params) + end + else + Map.put(params, to_string(config[:for] || key), nil) + end + + :list -> + for_name = to_string(config[:for] || key) + + if indexed_lists? do + params + |> Map.put_new(for_name, %{}) + |> Map.update!(for_name, fn current -> + if indexer do + Enum.reduce(form.forms[key], current, fn form, current -> + Map.put(current, indexer.(form), params(form, opts)) + end) + else + max = + current + |> Map.keys() + |> Enum.map(&String.to_integer/1) + |> Enum.max(fn -> -1 end) + + form.forms[key] + |> Enum.reduce({current, max + 1}, fn form, {current, i} -> + {Map.put(current, to_string(i), params(form, opts)), i + 1} + end) + |> elem(0) + end + end) + else + params + |> Map.put_new(for_name, []) + |> Map.update!(for_name, fn current -> + current ++ Enum.map(form.forms[key] || [], ¶ms(&1, opts)) + end) + end + end + end) + + if transform do + Map.new(untransformed_params, transform) + else + untransformed_params + end + end + + defp only_touched(form_keys, true, form) do + Enum.filter(form_keys, fn {key, _} -> MapSet.member?(form.touched_forms, to_string(key)) end) - |> Enum.reduce(params, fn {key, config}, params -> - case config[:type] || :single do - :single -> - if form.forms[key] do - nested_params = - if form.forms[key] do - params(form.forms[key], opts) - else - nil - end - - if form.form_keys[key][:merge?] do - Map.merge(nested_params || %{}, params) - else - Map.put(params, to_string(config[:for] || key), nested_params) - end - else - Map.put(params, to_string(config[:for] || key), nil) - end - - :list -> - for_name = to_string(config[:for] || key) - - if indexed_lists? do - params - |> Map.put_new(for_name, %{}) - |> Map.update!(for_name, fn current -> - max = - current |> Map.keys() |> Enum.map(&String.to_integer/1) |> Enum.max(fn -> -1 end) - - form.forms[key] - |> Enum.reduce({current, max + 1}, fn form, {current, i} -> - {Map.put(current, to_string(i), params(form, opts)), i + 1} - end) - |> elem(0) - end) - else - params - |> Map.put_new(for_name, []) - |> Map.update!(for_name, fn current -> - current ++ Enum.map(form.forms[key] || [], ¶ms(&1, opts)) - end) - end - end - end) end + defp only_touched(form_keys, _, _), do: form_keys + @add_form_opts [ prepend: [ type: :boolean, @@ -2851,6 +2877,9 @@ defmodule AshPhoenix.Form do |> Enum.sort_by(fn {params, key} -> params["_index"] || key end) + + # rescue + # _ -> end defp indexed_list(other) do