I am learning Elm, and and had trouble understanding from the more complex examples (elm-spa-example, etc) how to split out the view/update functions into a new module. So I built a very simple example that does only that, and sharing here in case it might help someone else.
module Main exposing (Model, Msg(..), init, main, update, view)
import Browser
import Button
import Html exposing (Html, button, div, h1, map, text)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = init, update = update, view = view }
-- MODEL
type alias Model =
{ button : Button.Model }
init : Model
init =
{ button = Button.init
}
-- UPDATE
type Msg
= ButtonMsg Button.Msg
update : Msg -> Model -> Model
update msg model =
case Debug.log "update msg" msg of
ButtonMsg buttonMsg ->
{ model | button = Button.update buttonMsg model.button }
-- VIEW
view : Model -> Html Msg
view model =
div []
[ h1 [] [ text "elm button example" ]
, map ButtonMsg (Button.view model.button)
]
Button.elm:
module Button exposing (Model, Msg(..), init, update, view)
import Html exposing (Html, button, div, h1, text)
import Html.Events exposing (onClick)
-- MODEL
type alias Model =
Int
init : Model
init =
0
-- UPDATE
type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case Debug.log "Button.update msg: " msg of
Increment ->
model + 1
Decrement ->
model - 1
view : Model -> Html Msg
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]
The way you have done this is correct. You will tend to notice that whenever you do this, the lower level module ends up exporting (Model, Msg(..), init, update, view), and sometimes also subscriptions too.
It is also possible to split out lower level modules that only export some of these common functions and types too, perhaps just view or update related functions, depending on what you are doing.
I just wanted to make sure, since you are learning Elm for the first time, that you should not be overly eager with this component-like pattern. Sometimes it fits really well (say for pages in an SPA), and sometimes it is overkill (for adding a button). Of course, the best way to learn is to experiment with it and discover the trade-offs yourself. Richard’s talk is one of the best resources to consult on this topic:
Good points on not making everything a component in a module, which is likely the tendency for those of us coming from React. In the app I’m working on, I’m trying to split out pages into modules. This example (of splitting out a button into a module) is somewhat contrived (as you would not do this in a real app), but I wanted to start with a code sample everyone is familiar with and keep it simple to illustrate the concept.