Elm form application extension to include Age numbered entry

I follow this guide: http://guide.elm-lang.org/architecture/user_input/forms.html

The text makes sense to me, my question relates to the exercise that he lists at the bottom of the page. He asks me:

"Add an extra field for age and check that it is a number."

I'm having difficulty with this because the onInput function seems to accept only String input. It seemed strange to me that there is no equivalent for type="number" inputs.

However, this is my attempt, which does not work:

 import Html exposing (..) import Html.App as Html import Html.Attributes exposing (..) import Html.Events exposing (onInput) import String exposing (length) main = Html.beginnerProgram { model = model, view = view, update = update } -- MODEL type alias Model = { name : String , password : String , passwordAgain : String , age : Int } model : Model model = Model "" "" "" 0 -- UPDATE type Msg = Name String | Password String | PasswordAgain String | Age Int update : Msg -> Model -> Model update msg model = case msg of Name name -> { model | name = name } Password password -> { model | password = password } PasswordAgain password -> { model | passwordAgain = password } Age age -> { model | age = age } -- VIEW view : Model -> Html Msg view model = div [] [ input [ type' "text", placeholder "Name", onInput Name ] [] , input [ type' "password", placeholder "Password", onInput Password ] [] , input [ type' "password", placeholder "Re-enter Password", onInput PasswordAgain ] [] , input [ type' "number", placeholder "Age", onInput Age ] [] , viewValidation model ] viewValidation : Model -> Html msg viewValidation model = let (color, message) = if model.password /= model.passwordAgain then ("red", "Passwords do not match!") else if length model.password <= 8 then ("red", "Password must be more than 8 characters!") else ("green", "OK") in div [ style [("color", color)] ] [ text message ] 

The error I am getting is the following:

 -- TYPE MISMATCH ----------------------------------------------------- forms.elm The argument to function `onInput` is causing a mismatch. 58| onInput Age ^^^ Function `onInput` is expecting the argument to be: String -> a But it is: Int -> Msg 

Note. I know that I could create the Century tab as soon as another text input, but this exercise specifically asked me to verify that this is a "type of number." I guess this means that I have to keep it inside the model as Int.

I understand what a mistake is. I just want to know the idiomatic way to fix this in Elm. Thanks.

+6
source share
3 answers

Any user input from the onInput event is a string.

Your Model expects it to be Int

Use String.toInt to parse an integer value from a string value.

Adjust the update function to convert the type to Int and change the type signature to Age String

 Age age -> case String.toInt age of Ok val -> { model | age = val } -- Notify the user, or simply ignore the value Err err -> model 

Thus, you have the opportunity to notify the user of an error.

If the Maybe value suits you better, the whole operator can be simplified to:

 Age age -> { model | age = Result.toMaybe (String.toInt age) } 
+6
source

You will need the equivalent of onInput , but for one that works with integers. Based on how targetValue defined, you can do something similar with the addition of Json.Decode.int to parse it as a whole:

 onIntInput : (Int -> msg) -> Attribute msg onIntInput tagger = Html.Events.on "input" (Json.map tagger (Json.at ["target", "value"] Json.int)) 

Then you can use it as such:

 , input [ type' "number", placeholder "Age", onIntInput Age ] [] 
+1
source

For Elm 0.19, which uses the documentation for targetValue , the code becomes:

 import Html.Events import Json.Decode onIntInput : (Int -> msg) -> Attribute msg onIntInput tagger = Html.Events.stopPropagationOn "input" <| Json.Decode.map alwaysStop (Json.Decode.map tagger targetIntValue) targetIntValue : Decoder Int targetIntValue = Json.Decode.at ["target", "value"] Json.Decode.string |> Json.Decode.andThen (\value -> case String.toInt value of Just number -> Json.Decode.succeed number Nothing -> Json.Decode.fail "not a number") alwaysStop : a -> (a, Bool) alwaysStop x = (x, True) 

and then you can use onIntInput where you used onInput.

0
source

All Articles