Writing A Full Site in Phoenix and Elm

Part 3: Navigation From The Ground Up

Last Updated

Current Versions

Previous Post in this Series

Introduction

Refactoring the View Function

view : Model -> Html Msg
view model =
div [ class "elm-app" ]
[ Html.App.map ArticleListMsg (ArticleList.view model.articleListModel) ]
articleListView : Model -> Html Msg
articleListView model =
Html.App.map ArticleListMsg (ArticleList.view model.articleListModel)
view : Model -> Html Msg
view model =
div [ class "elm-app" ]
[ articleListView model ]
pageView : Model -> Html Msg
pageView model =
articleListView model
view : Model -> Html Msg
view model =
div [ class "elm-app" ]
[ pageView model ]

Modifying our Model for Navigation

type Page
= RootView
| ArticleListView
type alias Model =
{ articleListModel : ArticleList.Model
, currentView : Page
}
type Msg
= ArticleListMsg ArticleList.Msg
| UpdateView Page
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
ArticleListMsg articleMsg ->
let (updatedModel, cmd) = ArticleList.update articleMsg model.articleListModel
in ( { model | articleListModel = updatedModel }, Cmd.map ArticleListMsg cmd )
UpdateView page ->
({ model | currentView = page }, Cmd.none)

Changing Our Views

pageView : Model -> Html Msg
pageView model =
case model.currentView of
RootView ->
welcomeView
ArticleListView ->
articleListView model
welcomeView : Html Msg
welcomeView =
h2 [] [ text "Welcome to Elm Articles!" ]
import Html exposing (..)

Adding a Header for Navigation

header : Html Msg
header =
div []
[ h1 [] [ text "Elm Articles" ]
, ul []
[ li [] [ a [ href "#", onClick (UpdateView RootView) ] [ text "Home" ] ]
, li [] [ a [ href "#articles", onClick (UpdateView ArticleListView) ] [ text "Articles" ] ]
]
]
import Html.Attributes exposing (class, href)
import Html.Events exposing (onClick)
onClick (UpdateView RootView)
Function `onClick` is expecting 1 argument, but was given 2.77|                                     onClick UpdateView ArticleListView
^^^^^^^^^^^^^^^
Maybe you forgot some parentheses? Or a comma?
view : Model -> Html Msg
view model =
div [ class "elm-app" ]
[ header, pageView model ]

Firing Off Events When Switching Routes

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
ArticleListMsg articleMsg ->
let (updatedModel, cmd) = ArticleList.update articleMsg model.articleListModel
in ( { model | articleListModel = updatedModel }, Cmd.map ArticleListMsg cmd )
UpdateView page ->
case page of
ArticleListView ->
({ model | currentView = page }, Cmd.map ArticleListMsg ArticleList.fetchArticles)
_ ->
({ model | currentView = page }, Cmd.none)

Adding a Show Link to the Article List

type SubPage
= ListView
| ShowView Article.Model
type Msg
= NoOp
| Fetch
| FetchSucceed (List Article.Model)
| FetchFail Http.Error
| RouteToNewPage SubPage
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
NoOp ->
(model, Cmd.none)
Fetch ->
(model, fetchArticles)
FetchSucceed articleList ->
(Model articleList, Cmd.none)
FetchFail error ->
case error of
Http.UnexpectedPayload errorMessage ->
Debug.log errorMessage
(model, Cmd.none)
_ ->
(model, Cmd.none)
_ ->
(model, Cmd.none)
articleLink : Article.Model -> Html Msg
articleLink article =
a
[ href ("#article/" ++ article.title ++ "/show")
, onClick (RouteToNewPage (ShowView article))
]
[ text " (Show)" ]
renderArticle : Article.Model -> Html Msg
renderArticle article =
li [ ] [
div [] [ Article.view article, articleLink article ]
]

Adding an Article Show Component

module Components.ArticleShow exposing (..)import Components.Article as Article
import Html exposing (..)
import Html.Attributes exposing (href)
type Msg = NoOpview : Article.Model -> Html Msg
view model =
div []
[ h3 [] [ text model.title ]
, a [ href model.url ] [ text ("URL: " ++ model.url) ]
, br [] []
, span [] [ text ("Posted by: " ++ model.postedBy ++ " On: " ++ model.postedOn) ]
]

Modifying Our Main Component to Display the Show Component

import Components.ArticleShow as ArticleShow
type Page
= RootView
| ArticleListView
| ArticleShowView Article.Model
type Msg
= ArticleListMsg ArticleList.Msg
| UpdateView Page
| ArticleShowMsg ArticleShow.Msg
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
ArticleListMsg articleMsg ->
case articleMsg of
ArticleList.RouteToNewPage page ->
case page of
ArticleList.ShowView article ->
({ model | currentView = (ArticleShowView article) }, Cmd.none)
_ ->
(model, Cmd.none)
_ ->
let (updatedModel, cmd) = ArticleList.update articleMsg model.articleListModel
in ( { model | articleListModel = updatedModel }, Cmd.map ArticleListMsg cmd )
UpdateView page ->
case page of
ArticleListView ->
({ model | currentView = page }, Cmd.map ArticleListMsg ArticleList.fetchArticles)
_ ->
({ model | currentView = page }, Cmd.none)
ArticleShowMsg articleMsg ->
(model, Cmd.none)
case articleMsg of
ArticleList.RouteToNewPage page ->
case page of
ArticleList.ShowView article ->
({ model | currentView = (ArticleShowView article) }, Cmd.none)
_ ->
(model, Cmd.none)
_ ->
let (updatedModel, cmd) = ArticleList.update articleMsg model.articleListModel
in ( { model | articleListModel = updatedModel }, Cmd.map ArticleListMsg cmd )
ArticleShowMsg articleMsg ->
(model, Cmd.none)
pageView : Model -> Html Msg
pageView model =
case model.currentView of
RootView ->
welcomeView
ArticleListView ->
articleListView model
ArticleShowView article ->
articleShowView article
articleShowView : Article.Model -> Html Msg
articleShowView article =
Html.App.map ArticleShowMsg (ArticleShow.view article)

Conclusion

Check out my new book!

I am a software engineer, and now, published author! Check out my new book at https://www.packtpub.com/web-development/phoenix-web-development

I am a software engineer, and now, published author! Check out my new book at https://www.packtpub.com/web-development/phoenix-web-development