Getting started with Elm
| by jpic | elmThis article was created by Thomas Binetruy as he’s into R&D around Elm for YourLabs but maybe it will help you too !
Introduction
In this short tutorial, we create a basic counter application that changes the title color based on the counter value. We first define our state model, its transitions, and finally our view - function of our current application state.
Setup code
Here are the necessary imports:
elm import Browser import Html exposing (Html, button, div, text, h1) import Html.Events exposing (onClick) import Html.Attributes exposing (alt, class, classList, href, src, title, style)
main = Browser.sandbox { init = init, update = update, view = view }
The model
In elm, the idea is that your view is a function of some data. This data is defined in the model, that’s its purpose! Let’s see how we can define our model
elm type alias Model = { title : String , color1 : String , color2 : String , count : Int }
init : Model init = Model “Error 500” “red” “green” 0
Here, we are create a type alias, which is very similar to a C struct
. That is it allows us to define custom types.
In the above code, we create a constant (there are no mutable variables in Elm, so I’m calling them constants) called init
of type Model
. See how we define our constant ? It look quite similar to instantiating an object in OOP. After this code, init.title
equals “Error 500”, init.color1
is “red”, “green” is assigned to init.color2
. Finally, init.count
is 0. The value for init
defines our application state.
State transitions
Because in Elm our page is a function of our model, whenever we want to cause a change in our view, we shall mutate our model with transition functions which will the re-render our view based on the new values of our model: our new application state.
elm type Msg = Increment | Decrement
update : Msg -> Model -> Model update msg model = case msg of Increment -> Model model.title model.color1 model.color1 (model.count + 1)
Decrement ->
Model model.title model.color1 model.color2 (model.count - 1)
In the above code, we define 2 state transitions, one for incrementing init.count
and one for decrementing it. But really, if there isn’t a state transition for each of our state variables, then it means that we could remove them from our model. In this example, it makes no sense to have title
, color1
, and color2
in our model since we don’t define transitions for them.
So in the above code, we define a type alias Msg
which here is a Union type of Increment
and Decrement
which means that a constant of type Msg
can be one of Increment
or Decrement
. And whenever we will add a state transition to our application, we need to make sure to update our Msg
type.
After our Msg
type definition, we define our state transitions with function called update
. This function takes two arguments and returns a new state:
msg
of typeMsg
, the message our app is emitting requesting a state transition. In our case, it’s eitherIncrement
orDecrement
,model
of typeModel
, our current application state.
So our state transitions are function of the state!
In the implementation of our update
function, we test the value of the sent message. If it’s Increment
we return a new model different from our previous model only with the fact that the count
value is incremented by one. Similarly, we our message is Decrement
, we return a new state wil the count
decremented by 1.
Rendering
Finally, we define our view. Remember that our view is a function of our current state! Mutating this state via messages will re-render our view.
Bellow is a code where we define our view
component that uses a title
component.
elm type alias TitleProps = { title : String , color: String }
title : TitleProps -> Html Msg title t = h1 [ style “color” t.color, class “my-super-title” ] [ text t.title ]
view : Model -> Html Msg view model = div [] [ title (TitleProps model.title (if model.count > 5 then model.color1 else model.color2)) , button [ onClick Decrement ] [ text “-” ] , div [] [ text (String.fromInt model.count) ] , button [ onClick Increment ] [ text “+” ] ]
Notice that our view
function takes a model
argument of type Model
and returns an Html Msg
. This is different from our title
function which take a TitleProps
as an input and return an Html Msg
.
In view
, we return an html structure. Each element is defined as follows: elementType properties children
where properties
and children
are arrays of properties and children respectively.
Our button
elements have onClick
properties that call our Decrement
and Increment
messages and have a single text
child each.
We can also define a title
component that takes a title and a color as arguments and return an h1
with a few properties and a textual value. Then we can just call this title
component from our view
function.
Building
If you put your source files in src/
and called your Elm file Main.elm
, then you can compile your application with the following command:
sh elm make src/Main.elm
Which will produce a self contained index.html
with inlined javascript.
Conclusion
I hope that you found this introductory tutorial useful. We saw how to define an application state, state transitions, and how to compose our view function. With these few tools, one can already start building complex dynamic applications. The next steps are to look into asynchronous elm.