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 −
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.
The syntax for defining a command is as given below −
type Cmd msg
The message generated by the view is passed to the command.
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 −
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.
In this example, the application will communicate with the Numbers API – "http://numbersapi.com/#42".
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] ]
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 }
The application has the following three messages −
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)
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)
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. |
This is the entry point of the Elm project.
main = Html.program { init = init , view = view , update = update , subscriptions = subscriptions }
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.