In Elm I have a model with nested attributes like:
model =
{ name = ""
, disruptedFields =
{ advertising =
{ name = "Advertising"
, checked = False
}
, travel =
{ name = "Travel"
, checked = False
}
, utilities =
{ name = "Utilities"
, checked = False
}
}
}
disruptedFields
contains a list of values for checkboxes. When I click on the checkbox I send an update message to UpdateDisruptedField
, which currently looks like:
UpdateDisruptedField value ->
let
fieldCollection = model.disruptedFields
field = fieldCollection.advertising
in
{ model | disruptedFields =
{ fieldCollection | advertising =
{ field | checked = (not value) }
}
}
My update function is hard-coded to model.disruptedField.advertising
in the field
and advertising
variables. This is working for me, but I'm stuck making the function generic.
How do I pass the record into UpdateDisruptedField so I can make it generic?
This is a common problem for Elm apps with many input fields. There are two approaches for creating a generic update function to reduce code repetition.
Extend the message for update with identifier for an input and then add another level of switch with case checkboxType of
and handle the update with all the nested Records. Every time you will add a new field in the model, you will have to extend the update with an extra branch for handling the update.
Re-structure your model with Dictionaries and handle the update in a proper generic way.
I prefer the second option, because updating nested Records is a chore.
Please consider the following example:
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 }
Please note, that I've been using =>
operator to make Tuples look nicer.
disruptedFields
is now a Dictionary, that uses String
keys to identify every checkbox.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With