Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Elm to Submit a form without tracking the field values

Tags:

forms

elm

I have a very simple login form with username / password. Is there a way to POST this form to the server and check for a 200s response without having to go through the coding gymnastics required to track the value of each field character by character as the user types? (Yes, I understand that it is the Elm way to do things, but adding two fields to my model, two Msg with accompanying entries in update just seems like a lot of unneeded code for a simple login form, and storing the password in the model forever seems like a bad idea.)

I have read these two questions, and I have found the onSubmit event. However, I am not sure what to do once update receives the message that the onSubmit event has fired. I feel like there might be two ways forward and I can't figure out how to do either:

  • Create a POST request directly from the form and send it to the server
  • Grab the values of the two fields and package them up myself to send to the server.

I would use the default submit function, but I would prefer to login with an asynchronous request and not leave the page.

like image 254
John F. Miller Avatar asked Mar 07 '23 21:03

John F. Miller


1 Answers

Although I would do the gymnastics for this case, you can do another gymnastics with JSON decoder to get values from DOM and put them into a Msg. JSON decoder allows you to get any values from event object with JSON decoder as long as it’s property access instead of method call.

Another trick is that you can access input elements by name from the form element.

import Html exposing (Html)
import Html.Attributes as HA
import Html.Events as HE
import Json.Decode as Json exposing (Decoder)

type Msg
    = SubmitLogin String String

update : Msg -> Model -> Model
update msg model =
    case msg of
        SubmitLogin username password ->
            -- Do AJAX with username and password

decodeField : String -> Decoder String
decodeField name =
    Json.at
        [ "currentTarget"
        , name
        , "value"
        ]
        Json.string

decodeLoginForm : Decoder Msg
decodeLoginForm =
    Json.map2
        SubmitLogin
        (decodeField "username")
        (decodeField "password")

preventDefault : HE.Options
preventDefault =
    { preventDefault = True
    , stopPropagation = False
    }

onLoginSubmit : Html.Attribute Msg
onLoginSubmit =
    HE.onWithOptions
        "submit"
        preventDefault
        decodeLoginForm

view : Model -> Html.Html Msg
view model =
    Html.form
        [ onLoginSubmit ]
        [ Html.input
            [ HA.name "username"
            , HA.type_ "text"
            ]
            []
        , Html.input
            [ HA.name "password"
            , HA.type_ "password"
            ]
            []
        , Html.input
            [ HA.type_ "submit"
            , HA.value "Login"
            ]
            []
        ]
like image 108
Shuhei Kagawa Avatar answered Mar 24 '23 08:03

Shuhei Kagawa