Tagged with

This is the fifth post in a series of posts about Elm for JavaScript developers. If you're a JavaScript developer, and you want to know more about Elm, stay tuned to this series of posts or sign up for DailyDrip and check out all the episodes we have in our room topic.

Here is what we already see:

Today we will see how to deal with external inputs in our application, and how to deal with side effects in Elm.

Subscriptions are data coming from some external source. Commands are data that we send to the runtime to request it to do something for us that interacts with the outside world and send us back a message telling us how it went. Our very known update function perform request for the runtime to perform an action for us.

Subscriptions

Subscriptions allow us to listen to the outside world and turn things that happen into Msg inside our app. - Adams, Josh

Probably you already saw subscriptions when you were creating your Elm program.

main : Program Never Model Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

When we are not using subscriptions, we can use always Sub.none.

main : Program Never Model Msg
main =
    Html.program
        { init = init
        , update = update
        , view = view
        , subscriptions = always Sub.none
        }

Subscriptions are the way our application can listen for external inputs.

External inputs like:

  • Keyboard events
  • Mouse movements
  • Browser location changes
  • Websocket events
  • Timer events

Example 1 of Subscription

Let's see an example from the documentation about Subscriptions. We will subscribe to the keyboard and mouse.

Model

Our model is just an integer.

Messages

Our Messages will be:

  • MouseMsg Mouse.Position
  • KeyMsg Keyboard.KeyCode

So, these are the way the USER interacts with our app, in this case using the Mouse and the Keyboard.

These messages will be produced by our subscriptions, and we can handle them in our update.

Our Subscriptions

Subscriptions allow us to listen to the outside world and turn things that happen into Msg inside our app. In our case, we will have two subscriptions: one from our keyboard and another from our mouse.

subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Mouse.clicks MouseMsg
        , Keyboard.downs KeyMsg
        ]

Using Sub.batch allow us to listen a list of Subscriptions.

Once something happen in one of these subscriptions, they are turned into Msg, which we then deal with in our update function. deal with this in our update function.

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        MouseMsg position ->
            ( model + 1, Cmd.none )

        KeyMsg code ->
            ( model + 2, Cmd.none )

If our Msg comes from mouse, we will increment our model by 1. If it comes from our keyboard, we will increment by 2.

Our Entire code:


import Html exposing (Html, div, text, program)
import Mouse
import Keyboard


-- MODEL


type alias Model =
    Int


init : ( Model, Cmd Msg )
init =
    ( 0, Cmd.none )



-- MESSAGES


type Msg
    = MouseMsg Mouse.Position
    | KeyMsg Keyboard.KeyCode



-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ text (toString model) ]



-- UPDATE


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        MouseMsg position ->
            ( model + 1, Cmd.none )

        KeyMsg code ->
            ( model + 2, Cmd.none )



-- SUBSCRIPTIONS


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ Mouse.clicks MouseMsg
        , Keyboard.downs KeyMsg
        ]



-- MAIN


main : Program Never Model Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

You can see this example in the Ellie App. This is a simple example on how to use subscriptions.

Example 2 of Subscription

As a second example of using Subscription, we will use the code from the last blog post, about bitcoin price.

subscriptions : Model -> Sub Msg
subscriptions model =
    Time.every second (always GetBitcoinPrice)

Here we are using always. It is one of the Basics things from Elm. The function always will return always the same value.

So, just changing this in our last Elm program, it will make the HTTP request each second. Easy, right? Rather than constantly polling, we could listen to a websocket for price updates as well. These would use subscriptions too.

Commands

Commands are data we send to the runtime to request it to do something for us that interacts with the outside world and send us back a message telling how it went. - Adams, Josh

In our last program, we have used Commands. Commands let us make HTTP requests, generate random numbers, etc.

We use commands a lot, probably more than subscriptions.

Functions with side effects

In theory, function with side effects are forbidden in the language. Although, we need to have functions with side effects. Elm uses the concept of commands to handle this.

A function returns a command value which names the desired side effect.

So, every time, from now on, when you see a function returning a command, you will know this function has a side effect! However, this isn't the whole story. We're just describing a side effect, so it's still a pure function. The Elm runtime takes the data describing the side effect and performs it for us, ensuring that it's safe and keeping us from dealing with potential errors. This is just one more way Elm makes it easy to write applications with zero runtime errors.

Let's see some examples in the documentation:

  • generate random numbers:
generate : (a -> msg) -> Generator a -> Cmd msg
  • make an http request:
send : (Result Error a -> msg) -> Request a -> Cmd msg

All these functions result in side effects happening in the runtime, as they return commands.

Summary

Today we saw what are Commands and Subscriptions in Elm and how they are used.

Resources


83e0ca4e73f2305ece2c629dd4bba53f?s=184&d=mm

Franzé Jr. Software Engineer with experience working in multi-cultural teams, Franze wants to help people when he can, and he is passionate about programming and Computer Science. Founder of RemoteMeetup.com where he can meet people all over the World. When Franze is not coding, he is studying something about programming.