Objective: Write an app that uses Model-View-Update but is not a giant Main module.
Caveat: This might not be the best way to structure an Elm app. It’s just what I did.
What is the role of Main? Main, in this architecture, is aggregates submodules. It has no (business) logic of its own. This’ll make more sense below.
The elm example app in the docs starts with this trivial model:
We could move this to a counter module and change
Main.Model to a record like this:
The Msg Type
The model was easy.
The update and the view are more complicated.
We need a way to map the module’s
Msg type into something that
In the example,
Main.Msg is defined as:
Start by moving this to the counter module.
Next, we need to update Main.Msg to wrap this type.
So how does this change
Instead of processing the update directly, we need to delegate it to the module:
There’s a lot going on here. Let’s break it down.
caseto pattern match on
msglike we normally would.
Counter.update. We’re simply unwrapping the wrapped values and passing them to module’s
Main’s counter with the new model value we get back.
- Important. Use
Cmd.mapto wrap any
updatefunction might return. This gets it back into a type of
The view follows a similar, but simpler, pattern. To delegate to a view in a module, simply extract the html into a function and place it in the module.
Note that you need to use
Html.map to wrap
Counter.view’s return value.
This is because
Counter.view has return type
Html Counter.Msg, but
Main.view only understands
Html.map with an approprate
Main.Msg constructor fixes this problem.
Finally, we need to delegate events from subscriptions. This, again, follows the same pattern.
This is just one way to solve the problem. The downside is that there is a decent amount of boilerplate. The upside, though, is that there is no magic.
Did this article help?
blog comments powered by Disqus