maca/form-toolkit/1.0.3

NOTE: the latest version is 2.0.0

FormToolkit.Parse

Map the values of an input or group of inputs to any shape you want, if you know Json.Decode you know how to use this module ;)

type Parser id a

A parser that takes a tree of input data and returns a parsed result or an error if the decoding fails.

parse : Parser id a -> Field id -> Result (Error id) a

Parses an input.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


Field.text
    [ Field.value (Value.string "A string")
    , Field.required True
    ]
    |> parse string
--> Ok "A string"
Parser id a
-> Msg id
-> Field id
-> ( Field id, Result (Error id) a )

Updates an input with a message and parses it.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


Field.text
    [ Field.value (Value.string "A string")
    , Field.required True
    ]
    |> parse string
--> Ok "A string"
parseValidate : Parser id a -> Field id -> ( Field id, Result (Error id) a )

Parses an input and updates the tree revealing errors.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


Field.text
    [ Field.value (Value.string "A string")
    , Field.required True
    ]
    |> parseValidate string
    |> Tuple.second
-->  Ok "A string"

Traversing and parsing

field : id -> Parser id a -> Parser id a

Parse for a field with the given identifier using a provided parser.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


type Fields
    = FirstName
    | LastName


fields : Field Fields
fields =
    Field.group []
        [ Field.text
            [ Field.label "First name"
            , Field.identifier FirstName
            , Field.value (Value.string "Brian")
            ]
        , Field.text
            [ Field.label "Last name"
            , Field.identifier LastName
            , Field.value (Value.string "Eno")
            ]
        ]


fields
    |> parse (field FirstName string)
--> Ok "Brian"
string : Parser id String

Parses the input value as a String.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "A string") ]
    |> parse string
    --> Ok "A string"
int : Parser id Int

Parses the input value as an Int.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.int 10) ]
    |> parse int
    --> Ok 10
float : Parser id Float

Parses the input value as a Float.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.float 10.5) ]
    |> parse float
    --> Ok 10.5
bool : Parser id Bool

Parses the input value as a Bool.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.bool True) ]
    |> parse bool
    --> Ok True
posix : Parser id Posix

Parses the input value as a Time.Posix.

maybe : Parser id a -> Parser id (Maybe a)

Allows dealing with blank values without producing an error.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "A string") ]
    |> parse (maybe string)
    --> Ok (Just "A string")


Field.text []
    |> parse (maybe string)
    --> Ok Nothing
list : Parser id a -> Parser id (List a)

Parses a list of inputs using the given parser.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.repeatable [ ]
    (Field.text [ ])
    [ Field.updateAttribute (Field.stringValue "mango")
    , Field.updateAttribute (Field.stringValue "banana")
    ]
    |> parse (list string)
    --> Ok [ "mango", "banana" ]
oneOf : List (Parser id a) -> Parser id a

Tries a list of parsers in order until one succeeds.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "success!") ]
    |> parse (oneOf [ fail "not really ;)", string ])
    --> Ok "success!"




Field.text [ Field.value (Value.string "success!") ]
    |> parse (oneOf [ string, fail "not really ;)" ])
    --> Ok "success!"
stringLenient : Parser id String

Parses the input value as a String for strictAutocomplete, even when the text doesn't match an option.

formattedString : String -> Parser id String

Format a string parser with a mask pattern, updating the field's display value and cursor position.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "1234567890123456") ]
    |> parse (formattedString "{d}{d}{d}{d} {d}{d}{d}{d} {d}{d}{d}{d} {d}{d}{d}{d}")
    --> Ok "1234 5678 9012 3456"
    -- And input field displays: "1234 5678 9012 3456"
email : Parser id String

Returns the raw value of the input without any decoding.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "A string") ]
    |> parse value
    --> Ok (Value.string "A string")
json : Parser id Value

Converts the entire input tree into a JSON Value. Field name property will be used as the key, if an input name is not present the parser will fail.

Useful if you just want to forward the form values to a backend.

import FormToolkit.Field as Field
import FormToolkit.Value as Value
import Json.Encode


Field.group [ ]
    [ Field.text
        [ Field.label "First name"
        , Field.name "first-name"
        , Field.value (Value.string "Brian")
        ]
    , Field.text
        [ Field.label "Last name"
        , Field.name "last-name"
        , Field.value (Value.string "Eno")
        ]
    , Field.repeatable [ Field.name "fruits" ]
        (Field.text [ Field.name "fruit" ])
        [ Field.updateAttribute (Field.stringValue "mango")
        , Field.updateAttribute (Field.stringValue "banana")
        ]
    ]
    |> parse json
    |> Result.map (Json.Encode.encode 0)
    --> Ok "{\"first-name\":\"Brian\",\"last-name\":\"Eno\",\"fruits\":[{\"fruit\":\"mango\"},{\"fruit\":\"banana\"}]}"
succeed : a -> Parser id a

A parser that always succeeds with the given value, use for buiding decoding pipelines with andMap, or to chain parsers with andThen.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


type Special
    = SpecialValue


specialParse : Parser id Special
specialParse =
    string
        |> andThen
            (\strValue ->
                if strValue == "special" then
                    succeed SpecialValue


                else
                    fail "Nothing special"
            )




Field.text [ Field.value (Value.string "special") ]
    |> parse specialParse
    --> Ok SpecialValue
fail : String -> Parser id a

A parser that always fails with a custom error.

Maps, combinators and pipeline style decoding

map : (a -> b) -> Parser id a -> Parser id b

Transforms the result of a parser using a function.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.text [ Field.value (Value.string "a string") ]
    |> parse (map String.toUpper string)
    --> Ok "A STRING"
map2 : (a -> b -> c) -> Parser id a -> Parser id b -> Parser id c

Combines two parsers using a function.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


Field.group []
    [ Field.text
        [ Field.identifier "FirstName"
        , Field.value (Value.string "Iris")
        ]
    , Field.text
        [ Field.identifier "LastName"
        , Field.value (Value.string "Hefets")
        ]
    ]
    |> parse
        (map2 Tuple.pair
            (field "FirstName" string)
            (field "LastName" string)
        )
    --> Ok ( "Iris", "Hefets" )
(a -> b -> c -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id out

Combines three parsers using a function.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


type alias Person =
    { firstName : String
    , lastName : String
    , age : Int
    }


personParse : Parser String Person
personParse =
    map3 Person
        (field "FirstName" string)
        (field "LastName" string)
        (field "Age" int)


fields : Field String
fields =
    Field.group []
        [ Field.text
            [ Field.identifier "FirstName"
            , Field.value (Value.string "Penny")
            ]
        , Field.text
            [ Field.identifier "LastName"
            , Field.value (Value.string "Rimbaud")
            ]
        , Field.int
            [ Field.identifier "Age"
            , Field.value (Value.int 81)
            ]
        ]


fields
    |> parse personParse
--> Ok { firstName = "Penny", lastName = "Rimbaud", age = 81 }
(a -> b -> c -> d -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id d
-> Parser id out
(a -> b -> c -> d -> e -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id d
-> Parser id e
-> Parser id out
(a -> b -> c -> d -> e -> f -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id d
-> Parser id e
-> Parser id f
-> Parser id out
(a -> b -> c -> d -> e -> f -> g -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id d
-> Parser id e
-> Parser id f
-> Parser id g
-> Parser id out
(a -> b -> c -> d -> e -> f -> g -> h -> out)
-> Parser id a
-> Parser id b
-> Parser id c
-> Parser id d
-> Parser id e
-> Parser id f
-> Parser id g
-> Parser id h
-> Parser id out
andThen : (a -> Parser id b) -> Parser id a -> Parser id b

Chains together parsers that depend on previous decoding results.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


wordsParser : Parser id (List String)
wordsParser =
    string
        |> andThen
            (\strValue ->
                case String.words strValue of
                    [] ->
                        fail "No words"


                    words ->
                        succeed words
            )




Field.text [ Field.value (Value.string "red green blue") ]
    |> parse wordsParser
    --> Ok (["red", "green", "blue"])
andMap : Parser id a -> Parser id (a -> b) -> Parser id b

Incrementally apply parsers in a pipeline fashion.

import FormToolkit.Field as Field exposing (Field)
import FormToolkit.Value as Value


type alias Person =
    { firstName : String
    , lastName : String
    , age : Int
    }


type Fields
    = FirstName
    | LastName
    | Age


fields : Field Fields
fields =
    Field.group []
        [ Field.text
            [ Field.identifier FirstName
            , Field.value (Value.string "Penny")
            ]
        , Field.text
            [ Field.identifier LastName
            , Field.value (Value.string "Rimbaud")
            ]
        , Field.int
            [ Field.identifier Age
            , Field.value (Value.int 81)
            ]
        ]


personParse : Parser Fields Person
personParse =
    succeed Person
        |> andMap (field FirstName string)
        |> andMap (field LastName string)
        |> andMap (field Age int)




fields
    |> parse personParse
--> Ok { firstName = "Penny", lastName = "Rimbaud", age = 81 }

Input update and custom validations

(Field id -> a -> ( Field id, Parser id b ))
-> Parser id a
-> Parser id b

This function can be used for performing custom validations, for formatting the input value, and for mapping the result of parsing the field.

import FormToolkit.Field as Field
import FormToolkit.Value as Value


removeVowels : String -> String
removeVowels =
    String.replace "a" ""
        >> String.replace "e" ""
        >> String.replace "i" ""
        >> String.replace "o" ""
        >> String.replace "u" ""




Field.text [ Field.value (Value.string "the quick fox jumps over the lazy dog") ]
    |> parse
        (string
            |> andUpdate
                (\field str ->
                    ( Field.updateStringValue (removeVowels str) field
                    , succeed (removeVowels str)
                    )
                )
        )
    --> Ok "th qck fx jmps vr th lzy dg"
    -- And input field displays: "th qck fx jmps vr th lzy dg"