Phoenix Form
<.form for={@form} phx-submit="save_phoenix"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<.signature_pad field={@form[:signature]} class="signature-pad w-full max-w-none">
<:label>Sign here</:label>
<:clear_trigger>
<.heroicon name="hero-x-mark" />
</:clear_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.signature_pad>
<.action type="submit" class="button ui-accent">
Submit
</.action>
</.form>
defmodule MyAppWeb.SignatureFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
phoenix_form =
Phoenix.Component.to_form(%{"signature" => ""}, as: :signature_phoenix, id: "signature-live-form-phoenix")
{:ok, assign(socket, :phoenix_form, phoenix_form)}
end
def handle_event("save_phoenix", %{"signature_phoenix" => params}, socket) do
signature = params["signature"] || ""
{:noreply,
assign(
socket,
:phoenix_form,
Phoenix.Component.to_form(%{"signature" => signature}, as: :signature_phoenix, id: "signature-live-form-phoenix")
)}
end
end
Phoenix Form + Ecto
<.form for={@form} phx-change="validate" phx-submit="save"
class="flex flex-col gap-space-lg w-full max-w-xl"
>
<input type="hidden" name="signature_ecto[_sent]" value="1" />
<.signature_pad field={@form[:signature]} class="signature-pad w-full max-w-none" on_draw_end="signature_drawn">
<:label>Sign here</:label>
<:clear_trigger>
<.heroicon name="hero-x-mark" />
</:clear_trigger>
<:error :let={msg}>
<.heroicon name="hero-exclamation-circle" class="icon" />
{msg}
</:error>
</.signature_pad>
<.action type="submit" class="button ui-accent">
Submit
</.action>
</.form>
defmodule MyAppWeb.SignatureFormLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
ecto_form =
%MyApp.Forms.SignatureForm{}
|> MyApp.Forms.SignatureForm.changeset_validate(%{})
|> Phoenix.Component.to_form(as: :signature_ecto, id: "signature-live-form-ecto")
{:ok, assign(socket, :ecto_form, ecto_form)}
end
def handle_event("validate", params, socket) do
sparams = Map.get(params, "signature_ecto", %{})
changeset =
%MyApp.Forms.SignatureForm{}
|> MyApp.Forms.SignatureForm.changeset_validate(sparams)
|> Map.put(:action, :validate)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset, action: :validate, as: :signature_ecto, id: "signature-live-form-ecto")
)}
end
def handle_event("signature_drawn", %{"paths" => paths} = payload, socket) do
value =
if is_list(paths) and paths != [],
do: Enum.join(paths, "\n"),
else: Map.get(payload, "url", "") || ""
validate_ecto(socket, %{"signature" => value})
end
def handle_event("save", params, socket) do
sparams = Map.get(params, "signature_ecto", %{})
case MyApp.Forms.SignatureForm.changeset_validate(%MyApp.Forms.SignatureForm{}, sparams) do
%Ecto.Changeset{valid?: true} = changeset ->
_data = Ecto.Changeset.apply_changes(changeset)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(
MyApp.Forms.SignatureForm.changeset_validate(%MyApp.Forms.SignatureForm{}, sparams),
as: :signature_ecto,
id: "signature-live-form-ecto"
)
)}
%Ecto.Changeset{} = changeset ->
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset, action: :insert, as: :signature_ecto, id: "signature-live-form-ecto")
)}
end
end
defp validate_ecto(socket, params) do
changeset =
%MyApp.Forms.SignatureForm{}
|> MyApp.Forms.SignatureForm.changeset_validate(params)
|> Map.put(:action, :validate)
{:noreply,
assign(
socket,
:ecto_form,
Phoenix.Component.to_form(changeset, action: :validate, as: :signature_ecto, id: "signature-live-form-ecto")
)}
end
end
defmodule MyApp.Forms.SignatureForm do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :signature, :string
end
def changeset(form, attrs \\ %{}) do
form
|> cast(attrs, [:signature])
|> validate_required([:signature])
end
def changeset_validate(form, attrs \\ %{}) do
form
|> cast(attrs, [:signature])
|> validate_required([:signature], message: "can't be blank")
end
end