Level 2.5 - TEA TIME
The Elm architecture is made up of three parts: model
, view
and update
.
Model
The model is the state of our application.
The application state can consist of for example data fetched from an API, which page the user is currently viewing, the current state of an input form etc.
In Elm this is usually modeled with a record, defined by using a type alias
.
For example:
type alias Model =
{ userList : List User
, currentPage : Page
, nameInput : String
}
View
A function that takes the current application state as an argument and returns some HTML.
Update
A function that takes a "message", the current application state and returns an updated application state.
This message is modeled with a custom type, so usually the update
function consists of pattern matching on the message value.
Messages are events that happen in our application. These could be for example:
- User clicked the cancel button
- User clicked the exit button
- User entered some text in a text field
- We received some data from an API
Browser.sandbox
Browser.sandbox
is the simplest way to run an Elm application.
It takes only one argument; a record with a field for the initial application state (init
), a field for the update
function, and a field for the view
function.
With this, the Elm runtime will make sure that when there's some user-input in your application, the message will be sent to your update
function, and when you have updated your model it will be sent to the view
function so the HTML gets updated.
Let's examine Brower.sandbox
's type signature.
Browser.sandbox
: { init : modelType
, view : modelType -> Html msgType
, update : msgType -> modelType -> modelType }
-> Program () modelType msgType
Here we can see that because of Elm's static typing these three fields must "match" each other:
- The type of the initial model must match the type of the argument to the
view
function. - The type of messages returned from
view
(themsgType
part inHtml msgType
) must be the same type as the first argument toupdate
- The type of the second argument to
update
must match the type of the model
Browser.sandbox
returns a Program () modelType msgType
but you can forget about the () modelType msgType
part for now.
The important part is that it returns a Program
, which is just what the Elm runtime wants.
Html msgType
This part can seem a bit confusing, so let's look at lists first. A list in Elm has the type
List someType
. This means that it is a list where the elements are of typesomeType
. For example:
List Int
is a list of intsList String
is a list of stringsThe concept is the same for
Html msgType
. It says that the HTML "contains" somemsgType
; all messages that come from this bit of HTML will be of typemsgType
. For example:
Html Int
- messages from this HTML will be intsHtml String
- messages from this HTML will be stringIn practice we will use
custom types
for our messages as they are incredibly useful, but it is useful to realize that our messages could in principle be of any type.In the end, this means that when you hook up your
view
andupdate
functions usingBrowser.sandbox
, the messages sent toupdate
will be of the type contained in the HTML.
Exercise time
To practice using the Elm architecture we will create the "Hello, world" of interactive web applications; a counter app.
It will consist of one button for incrementing a number, one button for decrementing a number and a <span>
for showing the number.
You can use the following skeleton code to get quickly up and running:
module Main exposing (main)
import Browser
import Html exposing (..)
main =
Browser.sandbox
{ init = 0
, update = update
, view = view
}
type alias Model
= Int
type Msg
= NoOp
update : Msg -> Model -> Model
update msg model =
model
view : Model -> Html Msg
view model =
text "Hello, I'm a view"
Task:
- Implement the view function. It should output the following HTML (substitute
0
for the value of the model):
<div>
<button>-</button>
<span>0</span>
<button>+</button>
</div>
- Create messages for incrementing and decrementing the model
- These should be
constructor function
s for theMsg
type - When you have done this, use pattern matching on the value of
msg
(case msg of ...
) inupdate
.
- These should be
- Add onClick handlers on the two buttons
onClick
is a function from theHtml.Events
module. Import it by addingimport Html.Events exposing (onClick)
at the top of your file- It has the type
onClick : msgType -> Attribute msgType
. Remember also that the second argument of HTML nodes (button
in our case here) is of typeList (Attribute msgType)
When you have done this, you should be able to increment and decrement the number by clicking on the buttons!
Bonus level:
Can you modify the program so that you have buttons for incrementing/decrementing by 1, 5 and 10 without using more than two different messages?
Hint:
constructor function
s can take arguments