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