diff --git a/lib/phoenix_html/form.ex b/lib/phoenix_html/form.ex
index 794252d..1d4ab67 100644
--- a/lib/phoenix_html/form.ex
+++ b/lib/phoenix_html/form.ex
@@ -64,6 +64,8 @@ defmodule Phoenix.HTML.Form do
id: nil,
name: nil,
data: nil,
+ action: nil,
+ method: nil,
hidden: [],
params: %{},
errors: [],
@@ -74,6 +76,8 @@ defmodule Phoenix.HTML.Form do
source: Phoenix.HTML.FormData.t(),
name: String.t(),
data: %{field => term},
+ action: nil | atom() | String.t(),
+ method: nil | atom() | String.t(),
params: %{binary => term},
hidden: Keyword.t(),
options: Keyword.t(),
@@ -191,9 +195,9 @@ 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, method, 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?(
@@ -202,7 +206,8 @@ defmodule Phoenix.HTML.Form do
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 form1.action != form2.action or
+ form1.method != form2.method 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..afa5a6a 100644
--- a/lib/phoenix_html/form_data.ex
+++ b/lib/phoenix_html/form_data.ex
@@ -56,6 +56,10 @@ defprotocol Phoenix.HTML.FormData do
applies if the field value is a list and no parameters were
sent through the form.
+ * `:action` - The form action, such as the HTML `action` attribute
+ or LiveView action.
+
+ * `:method` - The form method, such as the HTML `method` attribute.
"""
@spec to_form(t, Phoenix.HTML.Form.t(), Phoenix.HTML.Form.field(), Keyword.t()) ::
[Phoenix.HTML.Form.t()]
@@ -79,6 +83,8 @@ 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)
+ {method, opts} = Keyword.pop(opts, :method, nil)
id = Keyword.get(opts, :id) || name
unless is_binary(id) or is_nil(id) do
@@ -93,6 +99,8 @@ defimpl Phoenix.HTML.FormData, for: Map do
params: params,
data: %{},
errors: errors,
+ action: action,
+ method: method,
options: opts
}
end
@@ -118,6 +126,8 @@ 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)
+ {method, opts} = Keyword.pop(opts, :method)
id = to_string(id || form.id <> "_#{field}")
name = to_string(name || form.name <> "[#{field}]")
@@ -133,6 +143,8 @@ defimpl Phoenix.HTML.FormData, for: Map do
id: id,
name: name,
data: default,
+ action: action,
+ method: method,
params: params || %{},
hidden: hidden,
options: opts
@@ -157,6 +169,8 @@ defimpl Phoenix.HTML.FormData, for: Map do
source: conn_or_atom_or_map,
impl: __MODULE__,
index: index,
+ action: action,
+ method: method,
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..bcc51ac 100644
--- a/test/phoenix_html/form_test.exs
+++ b/test/phoenix_html/form_test.exs
@@ -138,6 +138,13 @@ 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, method: "post")
+ refute input_changed?(form, %{form | action: :validate, method: "post"}, :foo)
+ assert input_changed?(form, %{form | action: :save}, :foo)
+ assert input_changed?(form, %{form | method: "put"}, :foo)
+ end
+
describe "access" do
test "without name and atom keys" do
form =