diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex index 794252d..67e8c8b 100644 --- a/lib/phoenix_html/form.ex +++ b/lib/phoenix_html/form.ex @@ -64,6 +64,7 @@ defmodule Phoenix.HTML.Form do id: nil, name: nil, data: nil, + action: nil, hidden: [], params: %{}, errors: [], @@ -74,6 +75,7 @@ defmodule Phoenix.HTML.Form do source: Phoenix.HTML.FormData.t(), name: String.t(), data: %{field => term}, + action: atom(), params: %{binary => term}, hidden: Keyword.t(), options: Keyword.t(), @@ -191,18 +193,32 @@ defmodule Phoenix.HTML.Form do @doc """ Receives two forms structs and checks if the given field changed. - The field will have changed if either its associated value or errors - changed. This is mostly used for optimization engines as an extension - of the `Access` behaviour. + The field will have changed if either its associated value, errors, + action, or implementation changed. This is mostly used for optimization + engines as an extension of the `Access` behaviour. """ @spec input_changed?(t, t, field()) :: boolean() def input_changed?( - %Form{impl: impl1, id: id1, name: name1, errors: errors1, source: source1} = form1, - %Form{impl: impl2, id: id2, name: name2, errors: errors2, source: source2} = form2, + %Form{ + impl: impl1, + id: id1, + name: name1, + errors: errors1, + source: source1, + action: action1 + } = form1, + %Form{ + impl: impl2, + id: id2, + name: name2, + errors: errors2, + source: source2, + action: action2 + } = form2, field ) when is_atom(field) or is_binary(field) do - impl1 != impl2 or id1 != id2 or name1 != name2 or + impl1 != impl2 or id1 != id2 or name1 != name2 or action1 != action2 or field_errors(errors1, field) != field_errors(errors2, field) or impl1.input_value(source1, form1, field) != impl2.input_value(source2, form2, field) end diff --git a/lib/phoenix_html/form_data.ex b/lib/phoenix_html/form_data.ex index 02eec75..0efc546 100644 --- a/lib/phoenix_html/form_data.ex +++ b/lib/phoenix_html/form_data.ex @@ -56,6 +56,8 @@ defprotocol Phoenix.HTML.FormData do applies if the field value is a list and no parameters were sent through the form. + * `:action` - The user defined action being taken by the form, such + as `:validate`, `:save`, etc. """ @spec to_form(t, Phoenix.HTML.Form.t(), Phoenix.HTML.Form.field(), Keyword.t()) :: [Phoenix.HTML.Form.t()] @@ -79,6 +81,7 @@ defimpl Phoenix.HTML.FormData, for: Map do def to_form(conn_or_atom_or_map, opts) do {name, params, opts} = name_params_and_opts(conn_or_atom_or_map, opts) {errors, opts} = Keyword.pop(opts, :errors, []) + {action, opts} = Keyword.pop(opts, :action, nil) id = Keyword.get(opts, :id) || name unless is_binary(id) or is_nil(id) do @@ -93,6 +96,7 @@ defimpl Phoenix.HTML.FormData, for: Map do params: params, data: %{}, errors: errors, + action: action, options: opts } end @@ -118,6 +122,7 @@ defimpl Phoenix.HTML.FormData, for: Map do {name, opts} = Keyword.pop(opts, :as) {id, opts} = Keyword.pop(opts, :id) {hidden, opts} = Keyword.pop(opts, :hidden, []) + {action, opts} = Keyword.pop(opts, :action) id = to_string(id || form.id <> "_#{field}") name = to_string(name || form.name <> "[#{field}]") @@ -133,6 +138,7 @@ defimpl Phoenix.HTML.FormData, for: Map do id: id, name: name, data: default, + action: action, params: params || %{}, hidden: hidden, options: opts @@ -157,6 +163,7 @@ defimpl Phoenix.HTML.FormData, for: Map do source: conn_or_atom_or_map, impl: __MODULE__, index: index, + action: action, id: id <> "_" <> index_string, name: name <> "[" <> index_string <> "]", data: data, diff --git a/test/phoenix_html/form_test.exs b/test/phoenix_html/form_test.exs index cb11c45..75fb40f 100644 --- a/test/phoenix_html/form_test.exs +++ b/test/phoenix_html/form_test.exs @@ -138,6 +138,12 @@ defmodule Phoenix.HTML.FormTest do assert input_changed?(form, form(%{"foo" => "bar"}), "foo") end + test "input_changed? with changed action or method" do + form = form(%{}, action: :validate) + refute input_changed?(form, %{form | action: :validate}, :foo) + assert input_changed?(form, %{form | action: :save}, :foo) + end + describe "access" do test "without name and atom keys" do form =