Bridges Peri schemas and Phoenix forms.
Validates (and coerces) raw params with Peri.decode/3, wraps the
result in a Peri.Form struct, and converts it into a
Phoenix.HTML.Form through the Phoenix.HTML.FormData protocol, so
schemas plug directly into Phoenix.Component.form/1 and the <.input>
component without Ecto.
LiveView round trip
@schema %{
name: {:required, :string},
age: {:coerce, :string, {:integer, {:gte, 18}}}
}
def mount(_params, _session, socket) do
{:ok, assign(socket, form: Peri.Phoenix.to_form(@schema))}
end
def handle_event("validate", %{"peri" => params}, socket) do
{:noreply, assign(socket, form: Peri.Phoenix.to_form(@schema, params))}
end
def handle_event("save", %{"peri" => params}, socket) do
case Peri.decode(@schema, params) do
{:ok, data} -> # persist, redirect...
{:error, _} -> {:noreply, assign(socket, form: Peri.Phoenix.to_form(@schema, params))}
end
endAnd in the template:
<.form for={@form} phx-change="validate" phx-submit="save">
<.input field={@form[:name]} label="Name" />
<.input field={@form[:age]} type="number" label="Age" />
</.form>
Summary
Functions
Validates params against schema and returns a Phoenix.HTML.Form.
Functions
@spec to_form(Peri.schema() | Peri.Form.t(), map(), keyword()) :: Phoenix.HTML.Form.t()
Validates params against schema and returns a Phoenix.HTML.Form.
Accepts the same options as Phoenix.HTML.FormData.to_form/2 (:as,
:id, :action, ...) plus :mode, which is forwarded to
Peri.decode/3 (:strict by default, :permissive to keep unknown
fields).
On success the form carries the validated data and no errors. On failure
errors are stored in changeset format (%{field => [{message, opts}]},
nested humanized maps under assoc keys) and the form action defaults to
:validate so LiveView shows the errors.
The first argument may also be an already built Peri.Form: with
non-empty params it revalidates against the stored schema (the update
path of a phx-change round trip); with no params it is converted as is.