iodevs / elm-validate

Elm validation library
https://package.elm-lang.org/packages/iodevs/elm-validate/3.0.2
BSD 3-Clause "New" or "Revised" License
2 stars 1 forks source link
hacktoberfest

elm-validate

This library helps with a validation of input forms and it's based on Enrico Buonanno lessons on egghead.io.

Install

elm install iodevs/elm-validate

Usage:

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.

ChangeLog

see CHANGELOG

License

BSD