I had a sharing session for Elixir community in Saigon about how to using Ecto without db for validating Phoenix form. Now I add this for people who just start to learn Elixir can see what can do with Ecto & Phoenix form.
For save time I just write an example for HTML form in LiveView.
As we known Ecto is very flexible library for Elixir application and people usually use Ecto like:
Actually, we can use only 2 modules are enough for casting & validating form: Ecto Changeset & Schema (you can use only Changeset module but with Schema much more convenience).
For example:
I declare Schema for Candidate module:
defmodule DemoEctoForm.Candidate do
use Ecto.Schema
import Ecto.Changeset
embedded_schema do
field :name, :string
field :bio, :string
end
def changeset(candidate, attrs \\ %{}) do
candidate
|> cast(attrs, [:name, :bio])
|> validate_required([:name])
|> update_change(:name, &String.trim/1)
|> validate_format(:name, ~r/^[a-zA-Z\s]+$/)
|> validate_format(:name, ~r/^\w+(?:\s+\w+){1,5}$/)
|> validate_format(:bio, ~r/^\w+(?:\s+\w+){2,25}$/)
end
end
A embedded schema with only 2 fields & a changeset/2 function for casting & validating values from submitted form.
For validating use can see one required field (:name
) and I add some regex for checking valid fields.
And at LiveView I defined a template:
~H"""
<div class="bg-red-600 text-white rounded-md">
<br>
<.form
id="candidate-form"
:let={f} for={@changeset}
phx-change="validate"
phx-submit="submit"
class="flex flex-col max-w-md mx-auto mt-8"
>
<h1 class="text-4xl font-bold text-center">New Candidate!</h1>
<br>
<.input field={f[:name]} placeholder="Nguyen Van Great" id="name" label="Full Name" />
<br>
<.input field={f[:bio]} placeholder="example: Elixir, Phoenix, Ecto, Hòzô" id="bio" label="Bio"/>
<br>
<.button type="submit">Add Candidate</.button>
<br><br>
</.form>
</div>
"""
I passed default changeset from mount event then use directly in form. See .form
and .input
My mount event:
def mount(_params, _session, socket) do
changeset = Candidate.changeset(%Candidate{})
{:ok, assign(socket, changeset: changeset)}
end
And add phx-submit
event to handle submitted form from user:
def handle_event("submit", %{"candidate" => candidate_params}, socket) do
changeset =
%Candidate{}
|> Candidate.changeset(candidate_params)
if changeset.valid? do
data = apply_action!(changeset, :update)
IO.puts "Candidate data: #{inspect(data, [pretty: true, struct: false])}"
Ets.add_candidate(data)
socket =
socket
|> put_flash(:info, "You added a candidate!")
|> redirect(to: ~p"/")
{:noreply, socket}
else
changeset =
%Candidate{}
|> Candidate.changeset(candidate_params)
{:noreply, assign(socket, changeset: changeset)}
end
end
I cast data from submitted form to changeset then check if changeset is valid or not. If changeset is invalid I pass again socket for form show errors in browser then user can update data.
Now, I have a completed form!
Actually, I have added an other tips for user can continue fill to the form in another device/browser or in case if LiveView is crashed by save state of form to ets
table in my project.
Check my repo for more.
Top comments (0)