2016-07-23 48 views
4

嵌套记录在榆树我有嵌套属性的模型,如:如何使一个通用的更新功能在榆树

model = 
    { name = "" 
    , disruptedFields = 
    { advertising = 
     { name = "Advertising" 
     , checked = False 
     } 
    , travel = 
     { name = "Travel" 
     , checked = False 
     } 
    , utilities = 
     { name = "Utilities" 
     , checked = False 
     } 
    } 
    } 

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

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

我的更新功能是硬编码在fieldadvertising变量model.disruptedField.advertising。这对我来说很有用,但我坚持让这个函数通用。

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

回答

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 } 

请注意,我一直在使用=>操作,使元组看起来更好。

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