This library helps with a validation of input forms and it's based on Enrico Buonanno lessons on egghead.io.
elm install iodevs/elm-validate
For example as a validation of
- the register / login /... form, see example directory in this repository or a live demo
- the input forms for your applications, see below very simplified an example.
Let say, you have an employee form by which you can add new an employee to your system. You want to save his a photo, a name, an email and an age. The form responds to record EmployeeForm
where for each input form is defined type Fields
.
For sending/fetching these data to/from server you'll need to define a record Employee
:
type alias Employee =
{ name : String
, email : String
, age : Int
, photo : ...
}
and functions for transforming between these two records formToEmployee
:
formToEmployee : EmployeeForm -> Result String Employee
formToEmployee form =
let
fieldOk =
withField Ok
valueOk =
withoutField Ok
in
toModel
Employee
( valueOk ( \item -> form.photo )
>> fieldOk( \item -> form.name )
>> fieldOk( \item -> form.email )
>> fieldOk( \item -> form.age )
)
form
and employeeToForm
:
employeeToForm : Employee -> EmployeeForm
employeeToForm employee =
{ name = preValidatedField employee.name
, email = preValidatedField employee.email
, age = preValidatedField employee.age
, photo = ...
}
Now if you have the record Employee
it's enough to write a decoder:
decodeEmployee : Decoder Employee
decodeEmployee = ...
and an encoder for him:
encodeEmployee : Employee -> Value
encodeEmployee employee = ...
Last step before sending data is their validation by OnSubmit
:
setValidityEmployeeForm : EmployeeForm -> EmployeeForm
setValidityEmployeeForm form =
let
name =
form.name
|> validate OnSubmit nameValidation
email =
form.email
|> validate OnSubmit emailValidation
age =
form.age
|> validate OnSubmit ageValidation
in
{ form
| name = name
, email = email
, age = age
}
where particular validations can be defined as:
nameValidation : Validator String String
nameValidation =
isNotEmpty "Name of employee is required."
emailValidation : Validator String String
emailValidation =
(isNotEmpty "Email of employee is required.")
|> composite (isEmail "Incorrect email.")
ageValidation : Validator String Int
ageValidation =
"You cannot employ a person younger than 10 year old or elder 100!"
|> isRange (isInt "Age must be integer number!") 10 100
Of course, also these validations you'll use that same a way as in previous Register form example. A relevant parts (messages InputEmail
, BlurEmail
, etc.) are same or similar and omitted here.
Finally, somewhere inside update
function will be:
SendEmployeeToServer employeeForm ->
let
form =
employeeForm
|> setValidityEmployeeForm
in
employeeForm
|> formToEmployee
|> Result.map
(\data ->
( { model
| form = form
}
, Http.post
{ url = ...
, body = Http.jsonBody (encodeEmployee data)
, ...
}
)
)
|> Result.withDefault
( model, Cmd.none )
GotEmployeeFromServer (Ok data) ->
( { model
| form = employeeToForm data
}
, Cmd.none
)
GotEmployeeFromServer (Err err) ->
...
where message SendEmployeeToServer
will be called by clicking "check" button at the employee form. Similarly for getting data you'll need GotEmployeeFromServer
message. This message is binded with command:
getEmployeeFromServer : Cmd Msg
getEmployeeFromServer =
Http.get
{ url = ...
, expect = Http.expectJson GotEmployeeFromServer (Decode.decodeValue decodeEmployee)
}
which will be used in init part and somewhere else in your app.
see CHANGELOG