A simple example of splitting view/update into a separate module

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.

Let me know if there is any way to improve this.

3 Likes

Including source here as well:

Main.elm:

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 "+" ]
        ]
1 Like

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:

3 Likes

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.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.