decoder : String -> Json.Decode.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
)
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"])
--> ]
valuesAppend : Value a -> Value a -> Value a
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"]
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
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
If there's only 1 occurrence of the field, we'd have decoded it as OneValue.
But semantically, we want to treat it as ManyValues of 1 item when we manyMap
OneValue 3
|> manyMap ((++) [ 2 ])
--> ManyValues [ 2, 3 ]
ManyValues [ 3 ]
|> manyMap ((++) [ 2 ])
--> ManyValues [ 2, 3 ]
manyWithDefault : List a -> Value a -> List a
OneValue 42
|> manyWithDefault [3]
--> [3]
ManyValues [42]
|> manyWithDefault [3]
--> [42]
field : 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))