The nested Elm architecture
When an application starts growing large we might want to break the application messages into discrete parts. For example:
- Root Application
- Page 1
- Page 2
- ...
Pattern
The nested Elm architecture is a way of achieving this.
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
import Sub
type alias Model =
{ count : Int
, subModel : Sub.Model
}
newModel : Model
newModel =
{ count = 0
, subModel = Sub.newModel
}
type Msg
= Increment
| Sub Sub.Msg
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
Sub subMessage ->
{ model
| subModel =
Sub.update subMessage model.subModel
}
view : Model -> Html Msg
view model =
div []
[ div [] [ text <| String.fromInt model.count ]
, button [ onClick Increment ] [ text "+1" ]
, Sub.view model.subModel |> Html.map Sub
]
main : Program () Model Msg
main =
Browser.sandbox
{ init = newModel
, view = view
, update = update
}
Note the Sub.view model.subModel |> Html.map Sub
in view
.
Sub.elm :
module Sub exposing (..)
...
type alias Model =
{ count : Int }
newModel : Model
newModel =
{ count = 0
}
type Msg
= Increment
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
{ model | count = model.count + 1 }
view : Model -> Html Msg
view model =
div []
[ div [] [ text <| String.fromInt model.count ]
, button [ onClick Increment ] [ text "+1" ]
]
This pattern comes with its own set of challenges like:
- Added boilerplate
- It is not simple for the child module to communicate with the parent module (see Translator).
So this pattern is best used sparingly.