Reputation: 83
I've recently started with Elm and I run into a problem with the update function. My goal is to split up my big Main.elm file into multiple smaller files, but to do this I first try to split up the main components into smaller components in the same file. For this I rely heavily on this very informative guide.
It is fairly straightforward to split the Model and init (which I already did for DiceRoller) and it is trivial for the View. Not so much for the Update unfortunately.
Currently, it looks like this (in the master branch of the Main.elm file)
type Msg = Change String
| Name String
| Password String
| PasswordAgain String
| Roll
| NewFace Int
| SearchImages
| NewSearchResult (Result Http.Error (List String))
| ChangeTermInput String
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Change newContent ->
({ model | content = newContent }, Cmd.none)
Name name ->
({ model | name = name }, Cmd.none)
Password password ->
({ model | password = password }, Cmd.none)
PasswordAgain password ->
({ model | passwordAgain = password }, Cmd.none)
Roll ->
(model, Random.generate NewFace (Random.int 1 100))
NewFace newFace ->
({ model | diceRoller = { dieFace = newFace} }, Cmd.none)
SearchImages ->
(model, getSearchResult model.termInput)
NewSearchResult (Ok newResult) ->
( { model | termResult = newResult }, Cmd.none )
NewSearchResult (Err _) ->
(model, Cmd.none)
ChangeTermInput term ->
({ model | termInput = term}, Cmd.none)
And I managed to get it a bit more refined, but this does not compile (also see this Main.elm in the refactoring branch):
type DiceRollerMsg = Roll
| NewFace Int
type Msg = Change String
| Name String
| Password String
| PasswordAgain String
| MsgForDiceRoller DiceRollerMsg
| SearchImages
| NewSearchResult (Result Http.Error (List String))
| ChangeTermInput String
updateDiceRoller : DiceRollerMsg -> DiceRoller -> DiceRoller
updateDiceRoller msg model =
case msg of
Roll ->
model
NewFace newFace ->
{ model | dieFace = newFace}
updateDiceRollerCmd : Msg -> Cmd Msg
updateDiceRollerCmd msg =
case msg of
Roll ->
Random.generate NewFace (Random.int 1 100)
NewFace newFace ->
Cmd.none
updateCmd : Msg -> Model -> Cmd Msg
updateCmd msg model =
Cmd.batch
[ updateDiceRollerCmd msg
, getSearchResult model.termInput
]
updateModel : Msg -> Model -> Model
updateModel msg model =
case msg of
Change newContent ->
{ model | content = newContent }
Name name ->
{ model | name = name }
Password password ->
{ model | password = password }
PasswordAgain password ->
{ model | passwordAgain = password }
MsgForDiceRoller msg ->
{ model | diceRoller = updateDiceRoller msg model.diceRoller}
SearchImages ->
model
NewSearchResult (Ok newResult) ->
{ model | termResult = newResult }
NewSearchResult (Err _) ->
model
ChangeTermInput term ->
{ model | termInput = term}
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
(updateModel msg model, updateCmd msg model)
It fails to compile with a type mismatch on the line Role in updateDiceRoller, because the pattern matches DiceRollerMsg, but it is trying to match Msg. If I just change the input and return types to DiceRollerMsg I get: Function updateDiceRollerCmd
is expecting the argument to be: DiceRollerMsg But it is: Msg
Also I do not think that Cmd.batch in updateCmd is the best solution here.
I appreciate any input to making a better Elm app, also outside these questions.
Upvotes: 1
Views: 120
Reputation: 36385
Your compile errors originate from using Msg
as input and return values for updateDiceRollerCmd
while the case statement is using DiceRollerMsg
. You can fix this function by pattern matching from, and mapping to, MsgForDiceRoller
.
updateDiceRollerCmd : Msg -> Cmd Msg
updateDiceRollerCmd msg =
case msg of
MsgForDiceRoller Roll ->
Random.generate NewFace (Random.int 1 100)
|> Cmd.map MsgForDiceRoller
_ ->
Cmd.none
There is one more compile error in your view where you will need to change onClick Roll
to onClick (MsgForDiceRoller Rool)
Upvotes: 0