榆树中是否存在一种模式,用于避免编写大量消息以更新模型中子元素的各个字段?
目前,我最终得到的代码如下所示,每个输入的消息都会发生变化,然后是每个字段的一堆更新逻辑。我想要做的是有一个像AChanged这样的消息来处理对A的任何属性的所有更改。通过更新生成消息的函数中的记录或者通过传入字段名称然后使用它来直接执行尽可能在Javascript中更新记录。
module Main exposing (Model)
import Browser exposing (Document, UrlRequest)
import Browser.Navigation as Nav exposing (Key)
import Html exposing (div, input)
import Html.Events exposing (onInput)
import Url exposing (Url)
type alias A =
{ a : String
, b : String
, c : String
, d : String
}
type alias B =
{ e : String
, f : String
, g : String
, h : String
}
type alias Model =
{ key : Nav.Key
, url : Url.Url
, a : A
, b : B
}
type Msg
= UrlChanged Url.Url
| LinkClicked Browser.UrlRequest
| AaChanged String
| AbChanged String
| AcChanged String
| AdChanged String
| BeChanged String
| BfChanged String
| BgChanged String
| BhChanged String
init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init flag url key =
( Model key url (A "" "" "" "") (B "" "" "" ""), Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
view : Model -> Document msg
view model =
{ title = "Mister Mandarin"
, body =
div
[ input [ onInput AaChanged ] []
, input [ onInput AbChanged ] []
, input [ onInput AcChanged ] []
, input [ onInput AdChanged ] []
, input [ onInput BeChanged ] []
, input [ onInput BfChanged ] []
, input [ onInput BgChanged ] []
, input [ onInput BhChanged ] []
]
[]
}
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
case msg of
LinkClicked urlRequest ->
case urlRequest of
Browser.Internal url ->
( model, Nav.pushUrl model.key (Url.toString url) )
Browser.External href ->
( model, Nav.load href )
UrlChanged url ->
( { model | url = url }
, Cmd.none
)
AaChanged value ->
let
a =
model.a
newA =
{ a | a = value }
in
( { model | a = newA }, Cmd.none )
AbChanged value ->
let
a =
model.a
newA =
{ a | b = value }
in
( { model | a = newA }, Cmd.none )
AcChanged value ->
let
a =
model.a
newA =
{ a | c = value }
in
( { model | a = newA }, Cmd.none )
AdChanged value ->
let
a =
model.a
newA =
{ a | d = value }
in
( { model | a = newA }, Cmd.none )
BeChanged value ->
let
b =
model.b
newB =
{ b | e = value }
in
( { model | b = newB }, Cmd.none )
BfChanged value ->
let
b =
model.b
newB =
{ b | f = value }
in
( { model | b = newB }, Cmd.none )
BgChanged value ->
let
b =
model.b
newB =
{ b | g = value }
in
( { model | b = newB }, Cmd.none )
BhChanged value ->
let
b =
model.b
newB =
{ b | h = value }
in
( { model | b = newB }, Cmd.none )
main : Program () Model Msg
main =
Browser.application
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
, onUrlChange = UrlChanged
, onUrlRequest = LinkClicked
}
我为这个问题采取了两种截然不同的方法。给你最大控制权(同时仍然有助于消除冗长)的那个是将你的逻辑从Update
移动到你的View
,使用广义的Msg
。像:UpdateForm (String -> Model)
或UpdateForm (String -> FormModel)
。
另一种方法是完全放弃在模型中存储输入状态。这样做的缺点是不允许您执行初始化输入或轻松清除输入等操作。但它是一种快速而肮脏的方法来获取基本表格。在此方法中,您利用具有name
属性的输入元素成为父form
element1的属性这一事实。您可以将解码器附加到表单的onSubmit
并通过Decode.at ["ab", "value"]
获取值。
1https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-name