A data type representing the validity and error state of data, for example user-supplied input, with functions for combining results.
There are various ways of using the tools this library provides. The recommended way is to store ValidationResult state in your model, in much the same way as you store RemoteData in your model.
This means your form model is separate from the validated data model, and you typically need to map the form into the validated model (see example below).
Here's a simple example: a 'required' (String) input field, showing an error message below the input field as the user types.
First, define a form model with the field to be validated wrapped in a
ValidationResult:
type alias Model =
{ input : ValidationResult String }In your view,
pipe input through a validation function and into your update;
set the value to either the validated or the last-entered input; and
display any error message below the input element.
view : Model -> Html Msg view form = div [] [ input [ type_ "text" , value -- (2.) (form.input |> Validation.toString identity ) , onInput -- (1.) (Validation.validate isRequired >> SetInput ) ] [] , div -- (3.) [ class "error" ] [ text (Validation.message form.input |> Maybe.withDefault "" ) ] ]
Your validation functions are defined as a -> Result String a:
isRequired : String -> Result String String
isRequired raw =
if String.length raw < 1 then
Err "Required"
else
Ok rawOften you will want to validate input when the input loses focus (onBlur),
instead of immediately (onInput). ValidationResult supports this with the
Unvalidated state, which allows you to store input before validation (see
below, and full example here).
Also note if you do validate onInput as above, in most cases you should also
validate onBlur if the field is required.
Typically, you want to combine validation results of several fields, such that if all of the fields are valid, then their values are extracted and the underlying model is updated, perhaps via a remote http call.
This library provides andMap, which allows you to do this (assuming your
form model is Form, and your underlying validated model is Model):
validateForm : Form -> ValidationResult Model
validateForm form =
Validation.valid Model
|> Validation.andMap form.field1
|> Validation.andMap form.field2Using such a function, you can Validation.map the result into encoded form
and package it into an http call, etc.
Note that this library does not currently support accumulating validation errors
(e.g. multiple validations). The error message type is fixed as String. So
the andMap example above is not intended to give you a list of errors in the
Invalid case. Instead, it simply returns the first Initial or Invalid of
the applied ValidationResults.
For an approach that does accumulate validation errors, see elm-verify.
Run a validation function on an input string, to create a ValidationResult.
Note the validation function you provide is String -> Result String a, where
a is the type of the valid value.
So a validation function for "integer less than 10" looks like:
lessThanTen : String -> Result String Int
lessThanTen input =
String.toInt input
|> Result.andThen
(\i ->
if i < 10 then
Ok i
else
Err "Must be less than 10"
)Put a valid value into a ValidationResult.
Initialize a ValidationResult to the empty case (no input).
Initialize a ValidationResult to unvalidated input.
Map a function into the Valid value.
Chain a function returning ValidationResult onto a ValidationResult
Put the results of two ValidationResults together.
Useful for merging field ValidationResults into a single 'form' ValidationResult. See the example above.
Map over the error message value, producing a new ValidationResult
Extract the Valid value, or the given default
Extract the error message of an Invalid, or Nothing
Return True if and only if Valid. Note Initial and Unvalidated
results are False.
Return True if and only if Invalid. Note Initial and Unvalidated
results are False.
Convert a Maybe into either Invalid, with given message and input, or Valid.
Convert a Maybe into either Initial (if Nothing) or Valid (if Just)
Convert a Maybe into either Unvalidated, with given input, or Valid.
Convert a ValidationResult to a Maybe. Note Invalid and Unvalidated state is dropped.
Convert a Result into either Invalid, using given function mapping the Err
value to the error message (String), and the given input string; or Valid.
Note: this function may be useful for unusual scenarios where you have a
Result already and you need to convert it. More typically you would pass
a Result-returning function to validate — which calls fromResult
internally.
Convert a Result into either Initial (if Err) or Valid (if Ok).
Note Err state is dropped.
Convert a Result into either Unvalidated (if Err) or Valid (if Ok).
Convert the ValidationResult to a String representation:
Note: this is mainly useful as a convenience function for setting the value
attribute of an Html.input element.
A wrapped value has four states:
Initial- No input yet.Unvalidated- Input received but not yet validated, and here it is.Valid- Input is valid, and here is the valid (parsed) data.Invalid- Input is invalid, and here is the error message and your last input.