通过动态字段名称更新字段

Amp*_*aro 1 elm

我想使用动态字段名称更新字段。在我的示例中,我有两个div具有contenteditable属性。在blur事件我需要更新模型(每个 div 更新其字段)。

module UpdateTest exposing (main)

import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (on)
import Json.Decode as Json
import Debug

type alias Model =
    { field1 : String
    , field2 : String
    }

type Msg = Update String String

main : Program () Model Msg
main =
    Browser.element
        { init = init
        , subscriptions = subscriptions
        , view = view
        , update = update
        }

init : () -> ( Model, Cmd Msg )
init () =
    ( { field1 = "value 1", field2 = "value2" }, Cmd.none )

subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none

view : Model -> Html Msg
view model =
    div []
        [ div [ contenteditable True, attribute "data-id" "field1", onBlur (Update "field1") ] [ text model.field1 ]
        , div [ contenteditable True, attribute "data-id" "field2", onBlur (Update "field2") ] [ text model.field2 ]
        , div [ id "fiedl11" ] [ text model.field1 ]
        , div [ id "fiedl12" ] [ text model.field2 ]
        ]

onBlur : (String -> msg) -> Attribute msg
onBlur tagger =
    on "blur" (Json.map tagger targetTextContent) 

targetTextContent : Json.Decoder String
targetTextContent =
  Json.at ["target", "textContent"] Json.string

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Update id text ->
            ({model | id = Debug.log id text }, Cmd.none) -- here the issue
Run Code Online (Sandbox Code Playgroud)

你认为有什么更好的吗?

编辑:

我写了一个比真实例子更简单的例子,认为理解问题会更好。但是,字段的数量非常大,并且会通过用户操作动态增长。结构确实比较复杂,字段可以嵌套(4层),而且是有序的。你可以认为它是一个包含工作表、列、节和段落(所有这些元素都带有一个 id)的文本文档的模型。

编辑 2:也许,使用模型结构内部字段的路径来更新其值可能会更有趣。而不是使用它的 id。

Jes*_*sta 5

Elm 是一种静态类型语言,因此无法使用字符串值来引用记录的字段,因为这会导致在运行时发生类型错误。

Elm 还缺乏任何类型的运行时内省/反射,因此您无法在运行时获取类型信息,从而允许您根据记录的字段名称自动匹配字符串。

您需要执行以下操作:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Update id text -> case id of
            "field1" -> ({model | field1 = text }, Cmd.none)
            "field2" -> ({model | field2 = text }, Cmd.none)
Run Code Online (Sandbox Code Playgroud)