I am currently making an app in F# with fable elmish architecture where the record types are as follows (cut down to save space but you hopefully get the idea).
type NewOriginMerdEntry =
| AddOriginMerdID of string
| AddMerdNumber of int
| AddAverageWeight of float
| AddPD of int
type NewTreatmentEntry =
| AddTreatmentID of string
type NewDestMerdEntry =
| AddDestMerdID of string
....etc
Now I have compiled these into a discriminate union type such as this
type NewEntry =
| NewOriginMerdEntry of NewOriginMerdEntry
| NewTreatmentEntry of NewTreatmentEntry
| NewDestMerdEntry of NewDestMerdEntry
...etc
with finally the main message type looking like this:
type Msg = {
NewEntry of NewEntry
}
Which is clean enough however in the view function I need to create a new function for each type symbolizing a view and the specific messages that need to be dispatched when the text input changes.
Which is something like this:
let originMerdView (dispatch : Msg -> unit) (model : Model) =
let dispatch' = NewOriginMerdEntry >> NewEntry >> dispatch
let form = match model.form with
| OriginMerd o -> o
| _ -> None
R.scrollView[
P.ViewProperties.Style [
P.FlexStyle.FlexGrow 1.
P.BackgroundColor "#000000"
]
][
//these functions are simply calls to various input text boxes
inputText "ID" AddOriginMerdID dispatch'
numinputText "MerdNumber" AddMerdNumber dispatch'
floatinputText "average Weight" AddAverageWeight dispatch'
numinputText "PD" AddPD dispatch'
button "save" form SaveOriginMerd (SaveEntry >> dispatch)
]
let inputText label msg dispatch =
R.textInput[
P.TextInput.OnChangeText ( msg >> dispatch )
]
So first question is, would it be possible to somehow generalize this as the mainview will decide which of these functions to run based on the model state. It works fine but the amount of code repetition is fairly painful.
Also each new entry will get sent to this function:
let handleNewEntry (model : Model) (entry : NewEntry) =
match entry with
| NewOriginMerdEntry e -> handleNewOriginMerdEntry model e
... etc
let handleNewOriginMerdEntry (model : Model) (entry : NewOriginMerdEntry) =
let form =
match model.form with
| OriginMerd o -> match o with
| Some f -> f
| None -> OriginMerd.New
| _ -> failwithf "expected origin type got something else handleNewOriginMerd"
let entry =
match entry with
| AddOriginMerdID i -> {form with originMerdID = i}
| AddMerdNumber n -> {form with merdNumber = n}
| AddPD p -> {form with pD = p}
| AddAverageWeight w -> {form with averageWeight = w}
{model with form = OriginMerd (Some entry)}, Cmd.none
All the specific handle new entry functions are the exact same except with the different records obviously. This functions fine but again the code reuse is very painful. Is there some more elegant way of achieving the same result with less code repetition?