choonkeat/nativeform/2.1.0

NOTE: the latest version is 2.1.2

NativeForm

decoder : String -> Decoder (List ( String, Value String ))

Given the id attribute of a <form> tag, we can decode the current form values from the browser document.forms and into a List of key values.

view model =
    -- form with `id` attribute
    form [ id "edituserform123" ]
        -- fields with `name` attribute
        []


update msg model =
    ( { model
        | formFields =
            -- decode model.document.forms to obtain a list of
            -- form field values anytime
            model.documentForms
                |> Json.Decode.decodeValue (NativeForm.decoder "edituserform123")
                |> Result.withDefault []
      }
    , Cmd.none
    )

We are returning a List instead of Dict because on form submit, duplicate names are preserved. So we are preserving them here too.

If a Dict is desired, pipe to the valuesDict helper function

    update msg model =
    ( { model
        | formFields =
            -- decode model.document.forms to obtain a list of
            -- form field values anytime
            model.documentForms
                |> Json.Decode.decodeValue (NativeForm.decoder "edituserform123")
+               |> Result.map NativeForm.valuesDict
                |> Result.withDefault []
      }
    , Cmd.none
    )
type Value a
= OneValue a
| ManyValues (List a)

Values from form fields are either String or List String

e.g. values for input [ type_ "number" ] [] will still be a String since and is entirely up to your application to convert and validate it with String.toInt or String.toFloat

valuesDict : List ( comparable, Value a ) -> Dict comparable (Value a)

Given a list of key values, combine the values of duplicate keys

import Dict exposing (Dict)


valuesDict
    [ (1, OneValue "1")
    , (2, OneValue "a")
    , (2, ManyValues ["b","c"])
    , (3, ManyValues ["yes","no"])
    ]
--> Dict.fromList
-->     [ (1, OneValue "1")
-->     , (2, ManyValues ["a","b","c"])
-->     , (3, ManyValues ["yes","no"])
-->     ]

Given 2 Value, return a ManyValues

valuesAppend (OneValue "1") (OneValue "a")
--> ManyValues ["1","a"]


valuesAppend (OneValue "1") (ManyValues ["a","b"])
--> ManyValues ["1","a","b"]


valuesAppend (ManyValues ["1","2"]) (ManyValues ["a","b"])
--> ManyValues ["1","2","a","b"]


valuesAppend (ManyValues ["1","2"]) (OneValue "a")
--> ManyValues ["1","2","a"]

Helpers for OneValue

Example usage

toColor : Maybe (NativeForm.Value String) -> Result String Color
toColor maybeV =
    maybeV
        |> Maybe.map (NativeForm.oneMap colorFromString)
        |> Maybe.andThen (NativeForm.oneWithDefault Nothing)
        |> Result.fromMaybe "invalid color"
oneMap : (a -> b) -> Value a -> Value b
OneValue 3
|> oneMap ((+) 2)
--> OneValue 5


ManyValues [ 3 ]
|> oneMap ((+) 2)
--> ManyValues []
oneWithDefault : a -> Value a -> a
OneValue 42
|> oneWithDefault 3
--> 42


ManyValues [42]
|> oneWithDefault 3
--> 3

Helpers for ManyValues

Example usage

toHobbies : Maybe (NativeForm.Value String) -> Result String (List Hobby)
toHobbies maybeV =
    maybeV
        |> Maybe.map (NativeForm.manyMap (List.filterMap hobbyFromString))
        |> Maybe.map (NativeForm.manyWithDefault [])
        |> Result.fromMaybe "invalid hobby"
manyMap : (List a -> List b) -> Value a -> Value b
OneValue 3
|> manyMap ((++) [ 2 ])
--> ManyValues []


ManyValues [ 3 ]
|> manyMap ((++) [ 2 ])
--> ManyValues [ 2, 3 ]
manyWithDefault : List a -> Value a -> List a
OneValue 42
|> manyWithDefault [3]
--> [3]


ManyValues [42]
|> manyWithDefault [3]
--> [42]

Parsing form values into desired types

comparable
-> Result err a
-> Result (Dict comparable err) (a -> b)
-> Result (Dict comparable err) b

Pipe friendly builder of values that accumulates errors. Useful for writing your parseDontValidate functions

parseDontValidate : Time.Zone -> List ( String, NativeForm.Value String ) -> Result Errors ParsedInfo
parseDontValidate tz list =
    let
        dict =
            NativeForm.valuesDict list
    in
    Ok ParsedInfo
        |> field "myselect" (toRating (Dict.get "myselect" dict))
        |> field "myselectmulti" (toCharacteristics (Dict.get "myselectmulti" dict))
        |> field "mycheckbox" (toHobbies (Dict.get "mycheckbox" dict))
        |> field "mytext" (toNonEmptyString (Dict.get "mytext" dict))
        |> field "mynumber" (toInt (Dict.get "mynumber" dict))
        |> field "myurl" (toUrl (Dict.get "myurl" dict))
        |> field "mycolor" (toColor (Dict.get "mycolor" dict))
        |> field "mydate" (toTimePosix TypeDate tz (Dict.get "mydate" dict))
        |> field "mydatetime-local" (toTimePosix TypeDateTimeLocal tz (Dict.get "mydatetime-local" dict))
toNonEmptyString : Maybe (Value String) -> Result String String

parse a form field value into a String

See example/src/Main.elm for more functions