DEV Community

Mạnh Vũ
Mạnh Vũ

Posted on • Edited on

2

Using Ecto (without Db) for validating Phoenix form

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:

Ecto common case

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



Enter fullscreen mode Exit fullscreen mode

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>
    """


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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.

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay