#elmlang – Navigating the pages – part 3 View

So far, we have seen the Model and Update part of the navigation application. In this blog, we complete the whole project by connecting the final missing piece View.  First, let’s look at the output.

The first two lines on the screen are the two links—one to ‘All-Time Best’ and another to ‘Login.’ By default, ‘All-Time Best’ is set as Home, and if we pass any routes other than ‘Login,’ all routes will be routed to ‘All-Time Best.’ On page load, the page will look like the following; It loads ‘All-Time Best’ view.

image

When you click ‘Login,’ it will display the following.

image

In this example, if you notice, we have two sections, one is the top section, which contains hyperlinks to navigate, and then the view right below it to show the page’s content. For simplicity, we call the top section as header and the second part as the body. So view will contain the header and body.

view: Model –> Html Msg

view model =

div []

[ header

. body model

]

Like all the Elm applications, the view takes the model as input and generates the Html to generate messages. The model has two functions: header and the second one is body, which takes the model as a parameter.

Let’s review the header function first.

header: Html Msg

header =

div []

[ h3 []

[ a [ href “#alltimebest” ] [ text “All Time Best “ ]

, a [ href “#login” ] [ text “ Login” ]

]

]

The header function takes no parameter but generates Html. This function creates two hyperlinks (a tag). The only thing we need to pay attention to is the first parameter to href function. This string must match the strings in the update function.

case (hash) of
“#alltimebest” ->
AllTimeBest

“#login” ->
Login

Next, let’s define the body function.

body:Model –> Html Msg

body model =

case (model.page) of

AllTimeBest –>

alltimebest model

Login –>

login model

As you can imagine, we need to make sure we display an appropriate body based on the page requested. We did not display anything during the update function—all we did to change the page to the appropriate page in the model. Based on the page information in the model, we need to make sure we need to render appropriate content.

Based on the output we saw earlier, the all-time best and login function has nothing but a text to show page change happened. The function definitions of the pages are below.

alltimebest: Model –> Html Msg

alltimebest model =

h1 [] [ text “All Time Best” ]

login: Model –> Html Msg

login model =

h1 [] [ text “Login “]

Events leading up to view are

  • When someone wants to change a page, they click on the hyperlink
  • when the hyperlink is clicked, elm generates a navigation message (UrlChange)
  • The message triggers the update function
  • In the update function based on the change request, we create a new model with the page type requested
  • On completion of the model change, the view function is called
  • the view will turn around and call the body function with the current model
  • In body function, we check the model’s page type. If the page type is AllTimeBest then we call the ‘alltimebest’ function to create Html otherwise, we call Login

In summary, navigation is straightforward and simple in Elm. The things we need to know are

  • Use Navigation.program to connect Model, Update, and View
  • Have Model with the field which can hold the current page
  • In an update, handle Urlchange event with location parameter to change the Model
  • In view, use the Model’s current page to render the page in question

#elmlang – Navigating the pages – part 2 Update

In our previous blog, we looked at the application’s model side when building a SPA with navigation. In this blog, we will look at the update.

To summarize, the model changes, when building a SPA with navigations, are

  • The model needs to know the current page.
  • Instead of representing the page as a string, in Elm explicitly state the page by union type.
  • Setup initial page that we need to load during application startup

In an  update, there are two things we need to do

  • Define all the events our application is going to support
  • Define the actions when the events occur

Defining events:

We moved away from the beginner program in our navigation program, and now we are using Navigation.program. As mentioned in the previous blog, this function has all the beginner program’s goodies and more. When we use Navigation.program, one of the things it does when there is a URL change will trigger an event called UrlChange with location details. Since we removed all the noise in the application, UrlChange is the only interesting event. So let’s define the events.

type Msg

= UrlChange Navigation.Location

Whenever a user clicks a hyperlink in a program that triggers a URL change, the Navigation function will trigger the UrlChange event with all the information regarding the new URL and its attributes. Everything regarding how to fire the event is all wrapped up in the Navigation package.

Define actions:

When a user clicks a hyperlink to a new page, on clicking a hyperlink, the navigation function will create an event called UrlChange with the new location the user wants to go to. Anytime a new event is fired, our update function will be called first, and there we need to satisfy the user request. The update is where we act on the URL change request. Let’s take a moment to talk about what are the things we would need to display a new page

  • in Elm architecture; one will not call the rendered page directly
  • In Elm architecture, you modify the model which will trigger rendering a page
  • In the update, all we need to do is identify the page user intends to go and modify the current page with page user’s requested page

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
UrlChange location –>
({ model | page = (findpage location.hash) },  Cmd.none )

As usual, we are updating the model with the appropriate value in the update. When someone clicks on the hyperlink, the clicked hyperlink string will be available in the location.hash, we will use that to identify the page user wants to navigate to. Identifying the page user wants to navigate is encapsulated in the findpage function as shown below

findpage: String –> Page

findpage hash =

case (hash) of

“#alltimebest” –>

AllTimeBest

“#login” –>

Login

– ->

AllTimeBest

This is a straightforward function, which takes URL location as an input string and returns the page union type.

In summary, when using Navigation.Program,

  • one clicks a navigation link, elm will trigger UrlChange event with the URL link user clicked
  • when an event is fired, elm will call the programs update function
  • in the update, the function identifies the page user wants to navigate to and update the model with the page name
  • when a model is updated rendering page will be triggered by calling view

In the next blog, we will see how to modify the view to handle page navigation

#elmlang – Navigating the pages – part 1 Model

So far, we could create a simple elm application that can display a hardcoded list of best opening credits. As you can imagine, when building non-trivial applications, we will end up with multiple views, and based on user requests, we may need to swap the body with proper views. In the olden days, every page was recreated and redrawn, and in the new SPA world, only the portion of the DOM elements are swapped out with proper views.

In the SPA, you can think of a page with a header, body, and footer. Whenever a user clicks some header options, the body will be swapped out with appropriate views.

In Elm, we solve this with navigation and routing. Everything I learned on navigation and routing came from the following three awesome links.

Instead of adding navigation to the existing project, we will tackle navigation without any noise. So for our project, we are planning to have the following user selections

  • All-time best
  • Personal best
  • Trending now
  • About
  • Login

As the user selects any one of the options above, we will show an appropriate view.

To make this exercise simple and easy to follow, we will focus on just two of the five actions above,

  • All-time best
  • Login

To get this one going, we need to add another elm-package called ‘Navigation.’

elm package install elm-lang/navigation

Next, instead of using the beginner program as the lynchpin to connect model, view, and update, we will use Navigation.program.

So why are we using the Navigation.program instead of the beginner program? As the name suggests, this package wraps a lot of navigation-related activities and makes our development easy. For starters

  1. Navigation.program is wrapped on top of the Html.beginnerprogram (HTML.program), so all the things we learned to love are still there and more.
  2. Navigation notifies us every time there is a URL change.
  3. It also allows us to change the navigation.
  4. It provides us with a rich set of information to know what changed during URL change.

Like all our previous applications, we will start with the model. For the time being, ignore our application aspect of it but focus on the navigation aspect. While we are navigating between pages, what is the one thing that we care about? We need to know which page we are in. So we need to capture that as a field in our model. Good start, we know our model has one field, and it holds the current page name possibly. So what type should it be? Traditional thinking would make us define it to be String. But remember, we are in Elm, and we want to be as explicit as possible. In that case, instead of defining it as a string, we could define it to be a union type of all known pages. So, let’s start by defining all the known pages.

type Page =

    AllTimeBest

  | Login

So we defined a union type that defines all the possible pages we are going to support. With that, our model should be something like the following.

type alias Model =

   { page : Page

   }

We defined the model, and the next step is defining the initial state of the application.

initstate: Model

initstate =

   { page = AllTimeBest

  }

So far, nothing new. That is all for the model part; next, we will see the update part.

You can find the full source code the example here is https://github.com/ksunair/bestopeningcredits/blob/master/simplenav.elm

#Elmlang – Displaying a list

In the last blog, we continued our project to display a single best opening credit with a simple model. In this blog, we will see how do we go about displaying a list of opening credits.

Let’s start with the model. In the previous example, what we had was just one record with title and URL. Now to show a collection, we need to create a list of records. Let’s see how we would define the list of records.

type alias Model = List

{  title: String

, url: String

}

All we did in this definition compared to the previous one was to add ‘List’ in the definition. Even though this definition is all and good, there will be times where you will need to pass just a single record between functions, like displaying one record. So we need to split the definition to represent a record and list of records. With that refactoring, the definition would look like this.

type alias Model = List

Record

type alias Record =

{  title: String

, url : String

}

Here we defined a single record definition as record and then created a Model, a list of records.

Next, we modify the initial data to hold more than one best opening credits. So I added True Detective season 2 opening credits.

initData : Model
initData =
[ { title = “Game of Thrones”
, url = https://www.youtube.com/embed/s7L2PVdrb_8
}
, { title = “True Detective Season 2”
, url = https://www.youtube.com/embed/GJJfe1k9CeE
}
]

There will be no change to update function as there are no user interactions yet.

The view is going to be interesting. So far, all the controls we have created are all just single controls that never displayed anything that is a collection.  How do we go about doing this?

Let’s look at the view from the previous blog.

view : Model -> Html Msg
view model =
div []
[ h1 [] [ text initData.title ]
, iframe [ width 420, height 315, src initData.url ] []

]

The above view function takes Model and creates the view for Elm to render. Now that we modified the Model to List, we need to modify the definition to be Record instead of Model to display a single record.

view : Record-> Html Msg
view record=
div []
[ h1 [] [ text record.title ]
, iframe [ width 420, height 315, src record.url ] []

]

This can not be the view, because view needs to generate all the records to display, so let’s change the name of the view to a different name to represent what it does, displaying a single record.

displayLine : Record -> Html Msg
displayLine record =
div []
[ h1 [] [ text record.title ]
, iframe [ width 420, height 315, src record.url ] []
]

Now we need to modify the view to call this function for every record in the list, that is it. In Elm, there is no iteration or loop; instead, we will call the map function.

view : Model -> Html Msg
view model =
div []
(List.map displayLine model)

Let’s look at the view definition closer. View definition states that it takes Model (which is a list of records) and generates the HTML view for Elm to render. The view function definition has just one function call that is div. As stated in the previous blog, view function takes two arguments. The first set of arguments are the function attributes, and the second set of arguments is a list of children.  In the above definition, the second parameter is (List.map displayLine model), what does it mean?

Let’s look at the definition from left to right. There are three words in the statement. ‘List.map,’ ‘displayLine,’ and ‘model.’  We know the last two, ‘displayLine,’ which takes a record and displays the record’s title and url. The last parameter is ‘model,’ which is a list of records. So it looks like we are calling List.map function, with two parameters.

List.map’s first argument is a function that takes a list as a parameter and produces a list as a result.

If you look at our call, listen to displayLine for every record in the model, and generate a one-line display for the given record. List.map function always returns a list. Like all HTML function calls, Div function expects the second argument to be a list of children, and List.map returns the list of displayLine.

If you run the application, you should see a result similar to the following.

image

You can find the latest  code @ https://github.com/ksunair/bestopeningcredits

Let’s work on displaying single best opening credit – Elm

Continuing our project to display the best opening credits, let’s jump in start displaying hardcoded single best opening credit.

Before we start coding, let’s refresh quickly on the anatomy of Elm architecture. In Elm application, you have three separate parts, each doing its one task and one task only. The three components are

  • Model: This defines the datastore, and it also defines the initial state of an application.
  • Update: This section defines all the actions/events application supports and what do with the state of the application.
  • View: This defines the view of the application based on the state of the application.

Elm architecture is a straightforward one. In Elm, all the application state is maintained separately in the model.  On application start, Elm runtime will render the view using the initial state of the model. In the view, we define what all the events a user will be able to initiate are. When a user initiates an action or triggers an event, Elm run time will call the update function and pass in the incoming event/message and current state of the model. The update will act on the current state based on the event and create a new state, the new state of the application will then trigger view to render a new view with the updated state of the data.

Now with basics under our belt, let’s write a code that displays single best opening credits.

Like all the applications, let’s create a model first. There are always two questions we need to ask when defining a model (there are more, but for creating a trivial application, two is enough)

1. What is the definition of the model? What fields do we need? For this simple application, all we need is ‘title’ and a link youtube video of the opening credit

type alias Model =
{ title : String
, url : String
}

2. Now we know what data definition is, let’s create the initial data we want to display.

initData : Model

initData =
{ title = “Game of Thrones”
, url = https://www.youtube.com/embed/s7L2PVdrb_8
}

I want to call out two things: first, the idea of using a comma at the beginning of the line instead of the end. When we look at it seems a good coding practice, it is more than that in Elm. Since Elm is a functional programming language, the way a function is called will be different if you miss a comma.

The type definition is that even though Elm can infer the types, I would strongly recommend being explicit in your code and declaring the types. It helps for future code refactoring and maintenance.

Next Update. Since this is a trivial application with no user interaction, we will define a dummy update function. Again we will continue to ask the same two questions.

  1. What are the events we are expecting?

type Msg
= DoNothing

This is a dummy event to satisfy the beginnerProgram function,

2. What to do when an update function is called?

update : Msg -> Model -> Model
update msg model =
initData

Since there are no events to start with, we are not acting on any events.

Finally, the view. In the view, we are displaying just one record. The title will be bold and then link to the youtube video.

view : Model -> Html Msg
view model =
div []
[ h1 [] [ text initData.title ]
, iframe [ width 420, height 315, src initData.url ] []

]

Our view has the main ‘div’ with two children, one is h1, and another one is an iframe.

h1 does not have any attributes but has a child text which displays the title.

iframe has attributes of height, width, and the URL source.

That is it,

the final component which connects all together is the main

main =
beginnerProgram { model = initData, view = view, update = update }

run the elm reactor which will start the localhost:80 and selecting Main.elm will produce the following result

image

Starting Opening Credit Project in Elm & Horizon

Finally, I found some time to start the project. I am doing this project in a way to learn Elm.  To do full end-to-end development focusing on front end development, I wanted some lightweight back-end service. Initially, I was thinking of doing it with nodejs, but I realized there is a better one, especially for rapid development. Horizon is meant for that. I do not know much about it yet. I am planning to use this project to learn both of them.

Created the baseline for the project at https://github.com/ksunair/bestopeningcredits

For this project, I am using the Atom editor.  I am using the following packages

git-plus – to better integrate with Git

elm-format

language-elm – Syntax highlighting and auto-completion

linter-elm-make – Lint Elm

The main objectives of these projects are

  1. User should be able to login to the site using social media logins
  2. Each user should be able to nominate any of their favorite opening credits
  3. Every user gets to vote for their top 10
  4. Show all-time top 10 based on all user votes
  5. Show last week, month top 10

With this project, I intend to look at the following

  • Creating modules to separate the concerns
  • Create unit tests
  • Make HTTP calls
  • Manage routing and navigation

The base project is set up, and next blog we will see how we can create a simple page to allow users to nominate the opening credits.

Elm is pure functional programming language

While preparing for my presentation on ‘Introduction to Elm,’ I tried to prove Elm is a truly functional program by showing this below.

add: Int –> Int –> Int

add x y =

x + y

In the above example, the add function is pure; add function always creates the same output for a given input. So calling Add 2 3 will always return 5. It does not have anything of global scope or side effects. So if I were to introduce a global variable, Elm would go through a compiler error. I was expecting the following code to produce a compiler error.

num: Int

num = 10

add: Int –> Int –> Int

add x y =

num + x + y

Elm did not complain, and it worked. So if I were to pass, add 2 3,  and the result will be15. So in my mind, because the function depends on the outside variable num and someone can change num from outside, the add function is not pure, and thus Elm is not a functional programming language.

So I posted the question in Elm Slack Channel, and @mfeineis answered, “Elm is pure, and num is immutable,” then it hit me. I assumed few things as a normal imperative programmer would. The num is a variable and can be changed easily, but num is not a variable in functional programming, and there is no variable in Elm. So you can’t change the value of num. With that knowledge, if you were to look at the function, the function name is incorrect, it should reflect the function’s proper intention and be ‘addnumwithxandy.’

@jessta reply summed up the answer “ `num` and `10` are interchangeable because Elm is ‘referentially transparent.’ There’s no difference between a value and a variable containing that value.”

For the people, I owe an explanation. Hopefully, this blog helps, and for those helped me on the slack channel, big thanks.

Working with backend services in Elm

Before we go past building trivial solutions, we need to understand one more concept in a trivial example scenario. How do we go about making backend calls? More preciously, how to connect and work with API calls.

We will start out by looking at the final result, and then we will go about building them. We are building a straightforward application that will show the current market value of bitcoin. When you start the application, you will see the following screen.

image

The screen shows the initial data of 0. On pressing the ‘Get Data’ button, the application will make an API call to “https://api.cryptonator.com/api/ticker/ltc-usd”  URL, and display the result as it is on the screen.

image

It does not show the value; instead, it just displays the whole JSON payload as it is. We do not need to worry about parse JSON and other things for our API call discussion, which we will discuss later.

(It will be interesting to come back after a couple of years and recheck the value of bitcoin 🙂 )

Let’s start building the application without an API call first to get the basic screen shown.

First Model:

type alias Model =
{ rate : String
}

initData : Model
initData =
{ rate = “0”
}

We have just one field in the model record, which we kept is as String for the sake of simplicity.

To get started, we create the update section with

type Msg
= GetData

update : Msg -> Model -> Model
update msg model =
case msg of
GetData ->
dummyData

As you can expect, when a user clicks ‘GetData,’ the GetData message is fired by HTML. That is the only event we needed for the application right now. The action event on GetData does nothing but return dummy data. It is not making an API call yet.

The view is simple and straight forward. One label to show the rates and another button that initiates the GetData message.

view : Model -> Html Msg
view model =
div []
[ h3 [] [ text (“Current rate = ” ++ model.rate) ]
, button [ onClick GetData ] [ text “Get Data” ]
]

main =
Html.beginnerProgram { model = initData, view = view, update = update }

When you run the code first time, it will show the init data with 0.

image

On clicking GetData, it shows the dummy data as expected.

image

You can find the whole base code here in the Gist.

Time to add API call. There is one concept here that will look odd, but it is easy to understand. Before we go to the API call, I want to go one more time how HTML and our code interact.

view: Model –> Html Msg

update: Msg –> Model –> Model

In the above code snippet, the view takes the model and creates Html, capable of creating Msgs (like onClick or onInput). What goes into creating the message is hidden inside the Html module, and we do need to worry about; all we need to know when some user action happens, Msg will be triggered, and the ‘update’ function will be called immediately to act on it.

Now the same way, let’s think about API call; when we make an API call, we need to wait for the call to complete, and upon completion, we need to modify the model, and change in the model will update the view. Very simple. One difference between the button click event and the API event is that when API is called, there is a possibility the call might fail. So the result could come back as either successful (Ok resultValue) and the value or comeback with Error (Err _) with an error message. So we need to handle both the scenarios in the code on completion of the API call.

Let’s recap what we discussed so far

  • We need to treat API call similar to Html event calls
  • We need a mechanism to fire a message on completion of an API call
  • On completion, we need to test for the successful execution of API and error scenario

It seems there is a lot but not really. Let’s take baby steps and grasp the concept. To make API calls, we need to install the Http module. Once installed, let’s write the code to make the API call. To make an Http Get, we can use

Http.getString uri

this to make a call and get a string response from the URI. Simple. We could create a function that does it. But we have a problem, this returned string and we need to wait for it completely. We need to modify this somehow so that, on completion, it generates a message which we can act on when we get it. How do we go about doing it?

It is solved by Http.send function. Http.send function will return a message on completion of an HTTP request. So we can modify the previous statement to something like the following

Http.send HttpDataComplete (Http.getString url)

Http.Send is a command, which will initiate the Http.getString, and on completion, it will trigger HttpDataComplete event/msg. So if we were to write a function to do this task, it would be something like this

httpGetData: Cmd Msg

httpGetData, which does not get any input data, will generate a command capable of generating messages. Now let’s look at the implementation

httpGetData =

Http.send HttpDataComplete (Http.getString “https://api.cryptonator.com/api/ticker/ltc-usd”)

We have a function to get data. Now we need to call this function when Get Data button pressed.

Our current update function signature is

update: Msg –> Model –> Model

This reads, update function takes Msg and the current state of the model and generates a new model. But the changes we made when someone presses GetData button to generate the model and create a command that could create msg (like out view definition view : Model –> Html Msg). So our update definition now changes to

update: Msg –> Model –> (Model, Cmd Msg)

With that definition, when a user clicks on ‘GetData,’ we need to call the httpGetData function. We will do it something like the following

case msg of

GetData –>

(model, httpGetData)

if you look at the return state here, following the signature (Model, Cmd Msg).  Now that we made the call, how will we handle the response from getting a data call?

When you make an API call, you can get either a success or failure. On success, we change the rate value with result value. On failure, we need to reset it to initial data. In Elm, we have something Result which helps with this situation. Whenever we perform an operation that could result in success or failure, we need to use Result. With that, when Http make HttpDataComplete message, it will come back with results. So we need to modify the signature of our message to represent this scenario.

HttpDataComplete (Result Http.Error string)

Now in our update function, when we get HttpDataComplete, we need to check for success and failure.

case msg of

HttpDataComplete (Ok data) –>

HttpDataComplete (Err _) –>

The second (Err _) parameter means when you get an error with any value, perform that function.

Now we know we need to handle both the scenario, what should be done when API calls come back successful? All we need to do is modify the rate value in the model with incoming data. Now, if you remember, our update function expects the second parameter to a command generating function. After updating the model, we do not need to initiate any commands, so all we need to pass is Cmd.none. On error, reset the data model to initial data and the success scenario; the pass is no commands. So here is the completed update function.

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GetData ->
( model, httpGetData )

HttpDataComplete (Ok val) ->
( { model | rate = val }, Cmd.none )

HttpDataComplete (Err _) ->
( initData, Cmd.none )

We are not done yet, two more things we need to do. When we move to this program model, you might want to load data from back-end API on page load, which means we need to call that function without any program intervention. To accomplish that, we need to move to a different helper function called ‘program’ in Html.

Html.program takes a different set of parameters.

  • The first parameter is the initial data. It includes the initial model and any function that needs to be executed to load data from the back end. In this example, we are not expecting to load any data from API on load. So the values (model, Cmd.none)
  • Second is the view, and there are no changes to it.
  • The third parameter is the update function. No change there.
  • The final parameter is a subscription. For Http example, there is no subscription, so we will create a dummy subscription to satisfy the signature in a minute.

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

You can find the final source code for this here in this Gist.

Basic debugging in Elm

This blog purely focuses on very basic debugging. No time travel or anything fancy. Simple debugging features.

We will start with our basic code, which takes the first name and last name in two different input fields, and when the user pressed the ‘FullName’ button, it displays the firstname + lastname in Full Name: label.

image

The program I started out is here in the Gist. When you run the application and enter the first name and last name like the following, with that code.

image
and press FullName, you get the following result

image

The last name is missing, and the first name is added twice. (It is easy to fix, but we will continue as if we do not know the reasons).  So how do we go about debugging in the Elm?

For starters, when you run the elm in elm-reactor mode, the application runs in debug mode. When the application running in the browser, you will see a small box at the bottom right-hand side of the screen, something like the following.

image

If you click to open the window, you will see two sections.

One on the left shows all the events that triggered. The one on the right side shows the current state of the model.

image

This will be great means to see all the events that get fired and also for each event how the model changes.

The second approach is the age-old logging. Elm provides a means to log messages to the browser console. We will start with the first problem: the first name and last name show the first name twice.

We have the following code for Add message

Add ->
{ model
| fullName = model.firstName ++ model.firstName
, firstName = “”
, lastName = “”
}

even though it is obvious that we are adding the firstName field twice, we will add logs for the sake of showing logging. To add logs in Elm, you need to import the Debug package, which is already part of the Core package you have installed.

1. Import Debug

2. Add log messages to see what is the value of the two fields we are adding

Adding a log is pretty simple and very original. Before adding the log the Add event function was

Add ->

{ model

| fullName = model.firstName ++ model.firstName

, firstName = “”

, lastName = “”

}

To log, you do not need to create a separate line statement. You can do it inline like the following.

Add ->
{ model
| fullName = (log “first name : ” model.firstName) ++ (log “last name : ” model.firstName)
, firstName = “”
, lastName = “”
}

The log function takes two parameters, the first one is a string message, and the second parameter can be anything. Here is an interesting thing, in elm, when you have a log statement like this, the log function logs the message, but the underlying function (the original) executes normally. So, in reality, the before and after program statement is the same.

Open the developer console and execute the code and you will see the first and last name; both are the first name. Looking at the code, we know the instead of adding the last name, we were adding the first name.

image

Change the first name field to the last name and run the code with the log, and now we get a different message. Instead of repeating the first name twice, now it displays only the first name and not the last name.

image

You can find the code with logs here in this Gist. Now let’s look at why we are not getting the last name. We are going to use, time travel/history tab to see what is happening.  When a user enters a value in the input, for every keystroke onInput event fired. So let’s start there. We need to check and see if an appropriate action event is fired.

Based on the update event,

type Msg
= Add
| Clear
| InputFN String
| InputLN String

We expect InputLN event fired. Let’s open the tab and monitor the events.

First, I typed ‘unni,’ and you can see below, InputFN fired for each keystroke, and when I clicked FullName, you can see the Add event fired.

image

With this much information, we need to check whether we have the view wired up properly to fire the events on data entry.

, input [ onInput InputFN ] []
, input [] []

The error is obvious; for the second input box, we do not have an onInput event.

Adding the onInput and running the code gives the expected answer.

image

This is the first stab at the debugging in Elm. You can find the final version of the code here in this Gist.