使用 Elm 提交表单而不跟踪字段值

Using Elm to Submit a form without tracking the field values

我有一个非常简单的带有用户名/密码的登录表单。有没有一种方法可以将此表单 POST 发送到服务器并检查 200 秒的响应,而无需在用户键入时逐个字符地跟踪每个字段的值所需的编码体操? (是的,我知道它是 ,但是在我的模型中添加两​​个字段,两个 Msg 以及更新中的伴随条目似乎是一个简单的登录表单的大量不需要的代码,并将密码存储在永远模型似乎是个坏主意。)

我已阅读 个问题,并且找到了 onSubmit 个事件。但是,我不确定 update 收到 onSubmit 事件已触发的消息后该怎么做。我觉得可能有两种前进方式,但我不知道该怎么做:

我会使用默认的提交功能,但我更愿意使用异步请求登录而不离开页面。

Is there a way to POST this form without having to go through the coding gymnastics required to track the value of each field character by character as the user types?

没有。为此,需要将表单输入中的值从 DOM 中提取出来。榆树阻止你这样做,所以是的,你需要光荣的体操。

...storing the password in the model forever seems like a bad idea.

使用完密码后,您无需保留密码。有很多方法可以解决这个问题。您可以使用空 String 清除它,或使用 Maybe String,或使用总和类型(标签)作为模型的根而不是典型的产品类型(记录),这样您就可以有效在 运行 时切换 模型。你有选择权。

I am not sure what to do once update receives the message that the onSubmit event has fired.

onSubmit 触发时使用 Http module to construct a POST request. If the server will respond with data you need (other that status code) you will need to create a Json decoder 以便 Elm 可以解析数据并生成类型值(而不是一堆东西)。

此过程将生成 Request,然后您需要使用 Http.send 将其转换为 Cmd Msg 这将使您有机会告诉 Elm Msg 在服务器响应您的请求后发送到 updateMsg 的类型为 Result Http.Error YourType,您可以使用 Result 模块中的函数对其进行处理。

我遇到了同样的问题here,我还发现 elm 提交表单时很乏味,

假设这是您的观点:

import Html exposing (..)
import Html.Attributes exposing (..)
view : Model -> Html Msg
view model =
      Html.form [method "POST", action "/address"]
  [ input [ type_ "text" ,name "user"] [],
  input [ type_ "password", name "password"] [],
  input [ type_ "submit" ,value "Submit"] []
  ]

这就是我想出的:

将提交按钮替换为:

  input [ type_ "button" 
  ,value "Submit"
  ,attribute "onclick" "javascript:this.form.submit();"] []

显然,如果您不关心提交的 return 值,您可以混合任何需要的 javascript。

我知道这不是做事的"elm way",但它简单、实用而且有效。

虽然我会为这种情况做体操,但你可以用 JSON 解码器做另一个体操,从 DOM 中获取值并将它们放入 Msg. JSON 解码器允许您使用 JSON 解码器从事件对象获取任何值,只要它是 属性 访问而不是方法调用。

另一个技巧是您可以从表单元素按名称访问输入元素。

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"
            ]
            []
        ]