如何在Elm中为嵌套记录创建通用更新函数

BHO*_*OLT 5 elm

在Elm中,我有一个嵌套属性的模型,如:

model =
  { name = ""
  , disruptedFields =
    { advertising =
      { name = "Advertising"
      , checked = False
      }
    , travel =
      { name = "Travel"
      , checked = False
      }
    , utilities =
      { name = "Utilities"
      , checked = False
      }
    }
  }
Run Code Online (Sandbox Code Playgroud)

disruptedFields包含复选框的值列表.当我点击复选框时,我发送了一条更新消息UpdateDisruptedField,目前看起来像:

UpdateDisruptedField value ->
  let
    fieldCollection = model.disruptedFields
    field = fieldCollection.advertising
  in
    { model | disruptedFields =
      { fieldCollection | advertising =
        { field | checked = (not value) }
      }
    }
Run Code Online (Sandbox Code Playgroud)

我的更新函数model.disruptedField.advertisingfieldadvertising变量中被硬编码.这对我有用,但是我坚持让函数变得通用.

如何将记录传递到UpdateDisruptedField以便我可以将其设为通用?

hal*_*bra 6

这是具有许多输入字段的Elm应用程序的常见问题.有两种方法可用于创建通用更新函数以减少代码重复.

  1. 使用输入标识符扩展要更新的消息,然后添加另一级别的开关,case checkboxType of并使用所有嵌套记录处理更新.每次在模型中添加新字段时,都必须使用额外的分支扩展更新以处理更新.

  2. 使用词典重新构建模型,并以适当的通用方式处理更新.

我更喜欢第二种选择,因为更新嵌套的记录是一件苦差事.

请考虑以下示例:

module Main exposing (..)

import Html exposing (div, input, text, label)
import Html.App exposing (beginnerProgram)
import Html.Events exposing (onCheck)
import Html.Attributes exposing (type', checked)
import Dict


(=>) : a -> b -> ( a, b )
(=>) a b =
    ( a, b )


main =
    beginnerProgram { model = model, view = view, update = update }


model =
    { name = ""
    , disruptedFields =
        Dict.fromList
            [ "advertising"
                => { name = "Advertising"
                   , checked = False
                   }
            , "travel"
                => { name = "Travel"
                   , checked = False
                   }
            , "utilities"
                => { name = "Utilities"
                   , checked = False
                   }
            ]
    }


type Msg
    = Check String Bool


view model =
    let
        checkbox ( key, data ) =
            label []
                [ text data.name
                , input
                    [ type' "checkbox"
                    , checked data.checked
                    , onCheck (Check key)
                    ]
                    []
                ]
    in
        div []
            (model.disruptedFields
                |> Dict.toList
                |> List.map checkbox
            )


update msg model =
    case msg of
        Check checkboxId checked ->
            let
                updateRecord =
                    Maybe.map (\checkboxData -> { checkboxData | checked = checked })

                disruptedFieldsUpdated =
                    Dict.update checkboxId
                        updateRecord
                        model.disruptedFields
            in
                { model | disruptedFields = disruptedFieldsUpdated }
Run Code Online (Sandbox Code Playgroud)

请注意,我一直在使用=>运算符使元组看起来更好.

disruptedFields现在是一个词典,它使用String键来识别每个复选框.