Unlock the Power of Validations in Phoenix Live View: Ensuring Robust User Input

Michael Munavu
7 min readMay 21, 2023

--

Building seamless web applications with robust user experiences is crucial in today’s digital landscape. Phoenix Live View, an innovative framework built on Elixir, empowers developers to create real-time, reactive web applications. Validating user input is essential for maintaining data consistency and reliability, and Phoenix Live View offers a comprehensive and flexible validation system. This article explores the importance of validations in Phoenix Live View, demonstrates effective implementation techniques, and highlights the benefits of real-time error feedback. Discover how to unlock the potential of building error-free, interactive web experiences with Phoenix Live View validations.

We start by creating a new Phoenix Project .

% mix phx.new phoenix_liveview_validations

We configure the database username and password in config/dev.exs and then run

mix ecto.create 

to create the database.

For this article, we will be generating a live view for users.

We will create a users table with a name, email, password, password_confirmation, gender, and age.

To generate the live view template for this, the command will be as follows

in the terminal.

mix phx.gen.live Users User users name:string email:string password:string password_confirmation:string gender:string age:integer

You will see the following in your terminal.

You need to copy these routes and add them to lib/phoenix_liveview_validations_web/router. ex:

We would want to see the list of our users when we open the app, to do this, we need to ensure the root route (“/”) connects to the UserLive.index controller and index.

To do that,

We remove

get "/", PageController, :index

and also

 live "/user", UserLive.Index, :index

and replace it with

live "/", UserLive.Index, :index

This ensures we see the Live View template that shows all our users on the root page of the application.

Run

mix ecto.migrate

To migrate the database.

To start the application, we run

mix phx.server

When you go to

http://localhost:4000/

You see this.

Now let us add a new user, when you click New user, You see a modal that pops up as such.

We want to ensure every field has validated data to ensure we have the correct information added to our database.

Below are some of the different ways of adding validations, we shall be using the model created above.

For our case, we would want all fields to be present before saving to the database, we would like the age to be an integer and greater than 0 and less than 100.

We would want the email to contain an @ and for it to be unique for each user.

We would want the password and the password_confirmation to match and to as well have a minimum, maximum, or exact character count.

We would want the gender to either be “male” or “female”.

To do all these, we will need the validations that we are about to learn.

All these are written in lib/phoenix_liveview_validations/users/user.ex

in the changeset function.

1 . validate_required(changeset, fields, opts \\ [])

Validates that one or more fields are present in the changeset/data you are adding to the database

The syntax is as follows

|> validate_required(:field1)
|> validate_required([:field1 , :field2])

In Phoenix, the default validation ensures every field is required

|> validate_required([:name, :email, :password, :password_confirmation, :gender, :age]

if you want to customize the error message for validation, it would be as follows

 |> validate_required([:name, :email, :password, :password_confirmation, :gender, :age], message: "Please fill out this field")

2. validate_inclusion(changeset, field, data, opts \\ [])

Validates a change is included in the given enumerable/ range.

You would use this if you wanted the data that you are inserting to be included in a certain range of values(for a number) or to be either of the strings you want.

In our case, we would want the gender to be either male or female, the code would be as follows.

|> validate_inclusion(:gender, ["male", "female"])

It is advisable to customize error messages for a better user experience.

 |> validate_inclusion(:gender, ["male", "female"], message: "Gender has to be either male or female")

We would also want to ensure that the age is a number between 1 and 100,

the code for this would be.

 |> validate_inclusion(:age, 1..100 , message: "The age has to be a number between 1 and 100")

3 .validate_exclusion(changeset, field, data, opts \\ [])

Validates a change is not included in the given enumerable/ range.

You would use this when you do not want certain strings or values inserted into your database.

In this case, let’s say we did not want Either “admin@gmail.com” or “administrator@gmail.com” as an email, the validation code would be as follows

|> validate_exclusion(:email , ["admin@gmail.com" , "administrator@gmail.com"])

if you want to customize the error message for each exclusion validation, it would be as follows.

|> validate_exclusion(:title, ["Elixir", "Phoenix"], message:"The title must not be Ruby or Ruby on Rails")

4.validate_length(changeset, field, opts)

Validates a change/ data being added to the database is a string or list of the given length.

This validation ensures a string has a certain minimum or maximum length, we could use this for a password field or name field where we do not want a name that is either too short or too long.

You may also want a field to have a fixed length of characters.

|> validate_length(:name, min: 3) ,

this ensures the body has a minimum length of 3 characters

|> validate_length(:name, min: 3 , max: 20)

this ensures the name has a minimum length of 3 characters and a maximum length of 20 characters.

|> validate_length(:name, is: 6)

This ensures the name has a fixed character count of 6

if you want to customize the error message for each length validation, it would be as used in the above examples.

5. validate_number(changeset, field, opts)

Validates the properties of a number.

You would use this to ensure the data you add is a number.

|> validate_number(:age, greater_than: 0, message:"Age must be greater than 0")

For numbers, we can also use these as comparators.

  • equal_to: n
  • greater_than: n
  • greater_than_or_equal_to: n
  • less_than: n
  • less_than_or_equal_to: n

6.validate_format(changeset, field, format, opts \\ [])

Validates a change has the given format.

We can use this to validate emails for example, we would want every email to have an @

 |> validate_format(:email, ~r/@/)

if you want to customize the error message for each validation, it would be as follows.

|> validate_format(:email, ~r/@/ , message:"The email must contain an @")

We can also use this validation to ensure our passwords have at least 8 characters, one uppercase, one lowercase, and one number

|> validate_format(:password, ~r/(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}/, message: "Password must contain at least 8 characters, one uppercase, one lowercase and one number")

6.unique_constraint(changeset, field_or_fields, opts \\ [])

Checks for a unique constraint in the given field or list of fields.

You would use this to ensure every data inserted into a certain field is unique, for example, you would want to ensure every title is unique

First, you have to change the migration file to ensure the DB only has unique values of the title.

This will be in priv/repo/migrations .

We add the following code below the change function

create unique_index(:users, [:email])

Now the migration file looks like this

defmodule PhoenixLiveviewValidations.Repo.Migrations.CreateUser do
use Ecto.Migration

def change do
create table(:users) do
add :name, :string
add :email, :string
add :password, :string
add :password_confirmation, :string
add :gender, :string
add :age, :integer

timestamps()
end
create unique_index(:users, [:email])
end
end

now in the validations file , we add .

 |> unique_constraint(:email, message: "This email is already taken")

7.validate_confirmation(changeset, field, opts \\ [])

Validates that the given parameter matches its confirmation.

You would use this validation to ensure the password_confirmation field matches the password field

The syntax is as follows

    |> validate_confirmation(:fieldyouwanttoconfirm)

In our case , it will be

    |> validate_confirmation(:password, message: "Passwords do not match")

By leveraging the power of validations in Phoenix Live View, developers can ensure that user input remains accurate, secure, and error-free, ultimately delivering exceptional web experiences. If you’re eager to dive deeper into the code and explore practical implementation examples, feel free to check out the accompanying GitHub repository at [https://github.com/MICHAELMUNAVU83/phoenix_liveview_validations]. With the knowledge gained from this article and the resources provided in the repository, you’ll be well-equipped to harness the full potential of Phoenix Live View validations and build dynamic web applications that impress users with their seamless functionality and reliability. Happy coding!

--

--