Skip to content

Commit

Permalink
backport: add action field to form + input_changed
Browse files Browse the repository at this point in the history
Co-Authored-By: Chris McCord <[email protected]>
Co-Authored-By: José Valim <[email protected]>
2 people authored and SteffenDE committed May 30, 2024

Unverified

No user is associated with the committer email.
1 parent d6c9d53 commit d9323ea
Showing 3 changed files with 35 additions and 6 deletions.
28 changes: 22 additions & 6 deletions lib/phoenix_html/form.ex
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@ defmodule Phoenix.HTML.Form do
id: nil,
name: nil,
data: nil,
action: nil,
hidden: [],
params: %{},
errors: [],
@@ -71,6 +72,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(),
@@ -189,18 +191,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
7 changes: 7 additions & 0 deletions lib/phoenix_html/form_data.ex
Original file line number Diff line number Diff line change
@@ -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()]
@@ -86,6 +88,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, 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
@@ -100,6 +103,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do
params: params,
data: %{},
errors: errors,
action: action,
options: opts
}
end
@@ -146,6 +150,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, 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}]")
@@ -161,6 +166,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do
id: id,
name: name,
data: default,
action: action,
params: params || %{},
hidden: hidden,
options: opts
@@ -185,6 +191,7 @@ defimpl Phoenix.HTML.FormData, for: [Plug.Conn, Atom, Map] do
source: conn_or_atom_or_map,
impl: __MODULE__,
index: index,
action: action,
id: id <> "_" <> index_string,
name: name <> "[" <> index_string <> "]",
data: data,
6 changes: 6 additions & 0 deletions test/phoenix_html/form_test.exs
Original file line number Diff line number Diff line change
@@ -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 =

0 comments on commit d9323ea

Please sign in to comment.