タイトルの通り、施設個別ページの作成と、ルーティングの定義です。
ページ遷移時にどのような処理が行われるか、図があるとわかりやすいのですが自分で作るのが面倒なので、またあのページの"When the location changes"の図を参考にどうぞ。
前回、施設名をリンクにしたので、上記図中の「(1)Location change event」というところまでできています。これをトリガーにして、ページ遷移する部分を作ります。
elm-package install elm-lang/navigation
elm-package install evancz/url-parser
まずは、ブラウザでのURL変化を受け取って、モデルのRouteを変更するところまでです。
src/Models.elm
ルートを定義します。施設一覧ページ、施設個別ページ、not foundの3つです。また、ルートによって表示を変えるためには、モデルがルートを持っている必要があるため、モデルのフィールドにルートを追加します。それに伴って、initialModel
にもルートを追加しますが、これはブラウザのURによって決まる値なので、ここでは引数で受け取るようにしておきます。以下、変更・追記部分だけ載せます。
type alias Model =
{ facilities: WebData (List Facility)
, route: Route
}
initialModel : Route -> Model
initialModel route =
{ facilities = RemoteData.Loading
, route = route
}
type Route
= FacilitiesRoute
| FacilityRoute FacilityId
| NotFoundRoute
src/Routing.elm
リンクのクリック等によってURLが変化すると、NavigationライブラリがNavigation.Location
型のデータとしてURLを渡してくれます。URL文字列をパースしてRoute
に変換するparseLocation
とmatchers
を定義しましょう。このパース関数はUpdate.elm
とMain.elm
で使います。以下も、変更・追記部分だけ載せています。URLのパースには、url-parserを使っています。
import Models exposing (FacilityId, Route(..))
import Navigation exposing (Location)
import UrlParser exposing (map, oneOf, parseHash, Parser, s, string, top, (</>))
matchers : Parser (Route -> a) a
matchers =
oneOf
[ map FacilitiesRoute top
, map FacilityRoute (s "facilities" </> string)
, map FacilitiesRoute (s "facilities")
]
parseLocation : Location -> Route
parseLocation location =
case (parseHash matchers location) of
Just route ->
route
Nothing ->
NotFoundRoute
src/Msgs.elm
ルートの値の変更をトリガーにして表示を変える(ページ遷移)するため、新しいメッセージを定義します。
module Msgs exposing (..)
import Models exposing (Facility)
import Navigation exposing (Location)
import RemoteData exposing (WebData)
type Msg
= OnFetchFacilities (WebData (List Facility))
| OnLocationChange Location
src/Update.elm
上記のメッセージに対応するアップデートを定義します。
module Update exposing (..)
import Models exposing (Model)
import Msgs exposing (Msg(..))
import Routing exposing (parseLocation)
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Msgs.OnFetchFacilities response ->
( { model | facilities = response }, Cmd.none )
Msgs.OnLocationChange location ->
let
newRoute = parseLocation location
in
( { model | route = newRoute }, Cmd.none )
src/Main.elm
initialModel
の型が変わったため、それに合わせてinit
を修正します。ここでNavigation.Location
を受け取ってパースし、initialModelに渡します。メイン関数も修正します。プログラムがNavigation.Location
を受け取れるようにし、またその時にOnLocationChange
メッセージを送信します。以下、変更部分です。
import Navigation exposing (Location)
import Routing exposing (parseLocation)
init : Location -> (Model, Cmd Msg)
init location =
let
currentRoute = parseLocation location
in
( initialModel currentRoute, fetchFacilities )
main : Program Never Model Msg
main =
Navigation.program OnLocationChange
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
一旦ここで、コンパイルが通るか確認しましょう。ルーティングとモデルのアップデートまではできていますが、ビューをまだ変更していないため、ブラウザ上では何も変化は起きません。ではビューを作って行きましょう。
elmでwebアプリ作成10 〜 施設個別ページ