Elm - Commands



In the previous chapters, we discussed the various components of Elm architecture and their functions. The user and the application communicate with one another using Messages.

Consider an example, where the application needs to communicate with other components like an external server, APIs, microservice, etc. to serve the user request. This can be achieved by using Commands in Elm. Messages and commands are not synonymous. Messages represent the communication between an end user and the application while commands represent how an Elm application communicates with other entities. A command is triggered in response to a message.

The following figure shows the workflow of a complex Elm application −

Workflow

The user interacts with the view. The view generates an appropriate message based on the user's action. The update component receives this message and triggers a command.

Syntax

The syntax for defining a command is as given below −

type Cmd msg

The message generated by the view is passed to the command.

Illustration

The following example makes a request to an API and displays the result from the API.

The application accepts a number from the user, passes it to the Numbers API. This API returns facts related to the number.

The various components of the application are as follows −

Http Module

The Http Module of Elm is used to create and send HTTP requests. This module is not a part of the core module. We will use the elm package manager to install this package.

API

In this example, the application will communicate with the Numbers API – "http://numbersapi.com/#42".

View

The application's view contains a textbox and a button.

view : Model -> Html Msg
view model =
   div []
      [ h2 [] [text model.heading]
      ,input [onInput Input, value model.input] []
      , button [ onClick ShowFacts ] [ text "show facts" ]
      , br [] []
      , h3 [][text model.factText]
      ]

Model

The Model represents the value entered by the user and the result that will be returned by the API.

type alias Model =
   { heading : String
   , factText : String
   , input :String
   }

Message

The application has the following three messages −

  • ShowFacts
  • Input
  • NewFactArrived

Upon clicking the Show Facts button, ShowFacts message is passed to the update method. When the user types some value in the textbox, the Input message is passed to update method. Finally, when the Http server response is received, the NewFactArrived message will be passed to update.

type Msg
   = ShowFacts
   |Input String
   | NewFactArrived (Result Http.Error String)

Update

The update method returns a tuple, which contains the model and command objects. When the user clicks on the Show Facts button, the Message is passed to the update which then calls the NumbersAPI.

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
   case msg of
      Input newInput ->
      (Model "NumbersApi typing.." "" newInput ,Cmd.none)
      ShowFacts ->
         (model, getRadmonNumberFromAPI model.input)

      NewFactArrived (Ok newFact) ->
         (Model "DataArrived" newFact "", Cmd.none)

      NewFactArrived (Err _) ->
      (model, Cmd.none)

Helper Function

The helper function getRandomNumberFromAPI invokes the NumbersAPI and passes to it the number entered by the user. The result returned by the API is used to update the model.

getRadmonNumberFromAPI : String->Cmd Msg
getRadmonNumberFromAPI newNo =
   let
      url =
         "http://numbersapi.com/"++newNo
   in
      Http.send NewFactArrived (Http.getString url)
Sr. No. Method Signature Description
1 Http.getString getString : String -> Request String Create a GET request and interpret the response body as a String.
2 Http.send send:(Result Error a -> msg) -> Request a -> Cmd msg Send a Http request.

main

This is the entry point of the Elm project.

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

Putting it all together

Step 1 − Create folder CommandApp and file CommandDemo.elm.

Step 2 − Install http module using command elm package install elm-lang/http.

Step 2 − Type the contents for CommandDemo.elm as shown below −

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

main =
   Html.program
      { init = init
      , view = view
      , update = update
      , subscriptions = subscriptions
      }

-- MODEL
type alias Model =
   { heading : String
   , factText : String
   , input :String
   }

init : (Model, Cmd Msg)
init =
   ( Model "NumbersAPI" "NoFacts" "42"-- set model two fields
   , Cmd.none -- not to invoke api initially
   )

-- UPDATE

type Msg
   = ShowFacts
   |Input String
   | NewFactArrived (Result Http.Error String)

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
   case msg of
      Input newInput ->
      (Model "NumbersApi typing.." "" newInput ,Cmd.none)
      ShowFacts ->
         (model, getRadmonNumberFromAPI model.input)

      NewFactArrived (Ok newFact) ->
         (Model "DataArrived" newFact "", Cmd.none)

      NewFactArrived (Err _) ->
         (model, Cmd.none)

- VIEW

view : Model -> Html Msg
view model =
   div []
      [ h2 [] [text model.heading]
      ,input [onInput Input, value model.input] []
      , button [ onClick ShowFacts ] [ text "show facts" ]
      , br [] []
      , h3 [][text model.factText]
      ]

-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model =
   Sub.none

-- HTTP

getRadmonNumberFromAPI : String->Cmd Msg
getRadmonNumberFromAPI newNo =
   let
      url =
      "http://numbersapi.com/"++newNo
   in
      Http.send NewFactArrived (Http.getString url)

Step 4 − Fire the command.

C:\Users\dell\elm\CommandApp> elm make .\CommandDemo.elm

This will generate the html file as shown below.

Generate html
Advertisements