#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