Logo

dev-resources.site

for different kinds of informations.

Using Ecto (without Db) for validating Phoenix form

Published at
6/8/2024
Categories
ecto
liveview
phoenix
Author
manhvanvu
Categories
3 categories in total
ecto
open
liveview
open
phoenix
open
Author
9 person written this
manhvanvu
open
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.

liveview Article's
30 articles in total
Favicon
Phoenix LiveView, hooks and push_event: json_view
Favicon
Phoenix LiveView is slot empty?
Favicon
Bridging the Gap: Simplifying Live Component Invocation in Phoenix LiveView
Favicon
Optimize LiveView Performance with Temporary Assigns
Favicon
Phoenix LiveView Optimization Guide
Favicon
Better LiveView Hooks with Typescript
Favicon
Automatically clearing flash messages in Phoenix LiveView
Favicon
Debug and visualise TailwindCSS document structure
Favicon
Build a small chat service using Elixir and deploy it on Amazon ec2 using AWS (Part 1)
Favicon
Build a small chat service using Elixir and deploy it on Amazon ec2 using AWS (Part 2)
Favicon
Weather API: A GenServer and LiveView Implementation Part I
Favicon
Build a small chat service using Elixir and deploy it on Amazon ec2 using AWS (Last part)
Favicon
Backpex - a highly customizable admin panel for Phoenix LiveView applications
Favicon
AI powered app (with open-source LLMs like Llama) with Elixir, Phoenix, LiveView, and TogetherAI
Favicon
Using Ecto (without Db) for validating Phoenix form
Favicon
Adding stream_async() to Phoenix LiveView
Favicon
SaladUI - Implement avatar component for Phoenix LiveView
Favicon
Connectivity status with Phoenix LiveView
Favicon
Phoenix Liveview components for Shadcn UI
Favicon
Ash - Create with relationship
Favicon
My Failed Student Housing App
Favicon
Beter data-confirm modals in Phoenix LiveView
Favicon
Free Beginner Friendly LiveView Course in English and Portuguese
Favicon
LiveView + WebComponents = ๐Ÿš€
Favicon
Ash AshSqlite - Aggregates not supported
Favicon
Phoenix Liveview - open editor for element
Favicon
Ash Calculations - Cond
Favicon
How does Ecto.Schema's `has_one/3` works?
Favicon
Creating a Date Range Picker with Phoenix LiveView
Favicon
Listing matches for users

Featured ones: