Feb 2016

20

Reactive Apps With Elm Part 2

In the first part of this blog series we saw what Signals are. Let us continue on this journey and explore Mailboxes.

Mailbox

A mailbox has an address we can send messages to. We use mailboxes and signals to modify our applications current state over time. The norm is to call the Mailbox as inbox, but you can call it anything. To define an inbox you call Signal.mailbox function and it needs to have an initial value which is usually a NoOp Action.


inbox: Signal.Mailbox Action
inbox =
  Signal.mailbox NoOp
          

To subscribe to this Mailbox you need to register to its signal. This can be done by calling inbox.signal function.


actions: Signal Action
actions =
  inbox.signal
          

Finally we use the Mailbox's address to fire off any events that change our applications state. We do that by passing inbox.address to view in the main function and this accepting another argument for address in our view. Let us see this in action. Let us create a simple thumbs up/down app which stores the number of ups & downs in the model. We'll do this using a Mailbox.

We'll do things a bit differently here though. We don't want the styles that Elm provides on compiling. We are going to have our own styles and create our own index.html. We'll plugin in our javascript include and styles like this. Finally we'll compile the javascript like this


elm-make Thumbs.elm --output Thumbs.elm.js
          

<!-- index.html -->
<!DOCTYPE html>
<html>
  <head lang="en">
    <title>Thumbs</title>
    <meta charset="UTF-8">
    <script type="text/javascript" src="Thumbs.elm.js"></script>
    <link rel="stylesheet" href="thumbs.css">
  </head>
  <body>
  </body>
  <script type="text/javascript">
    var app = Elm.fullscreen(Elm.Thumbs);
  </script>
</html>
          

/* thumbs.css */
button{
  height: 4em;
  font-size: 0.8em;
  width: 4em;
}

.myBtn{
  margin-right: 50px;
}
          

-- Thumbs.elm
module Thumbs where

import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (..)

-- MODEL
type alias Model = { ups: Int, downs: Int }

initialModel: Model
initialModel =
  {
    ups = 0,
    downs = 0
  }

-- UPDATE

type Action = NoOp | Up | Down

update: Action -> Model -> Model
update action model =
  case action of
    NoOp ->
      model
    Up ->
      { model | ups = model.ups + 1 }
    Down ->
      { model | downs = model.downs + 1 }

-- VIEW

view: Signal.Address Action -> Model -> Html
view address model =
  div []
  [
    button [ class "myBtn", onClick address Down ]
      [ text ((toString model.downs) ++ " 👎") ],
    button [ onClick address Up ]
      [ text ((toString model.ups) ++ " 👍" ) ],
    p [] [ text (toString model) ]
  ]

inbox: Signal.Mailbox Action
inbox =
  Signal.mailbox NoOp

actions: Signal Action
actions =
  inbox.signal

model: Signal Model
model =
  Signal.foldp update initialModel actions

main: Signal Html
main =
  Signal.map ( view inbox.address) model
          

The Action Signal associated with the inbox updates based on user inputs called actions. These actions are used to transform the current model. This gives us a new Signal of model values and we apply the view function on these values using the inbox's address. Hence we call it dynamic, reactive webapp.

If you compile and open up the index.html on the web browser you should see something similar to this.

Thumbs Reactive Webapp

That concludes the second part of this blog series, in the last one we'll build a Todo webapp.




Tags: Elm