elm

elmでwebアプリ作成9 〜 施設個別ページとルーティング

タイトルの通り、施設個別ページの作成と、ルーティングの定義です。

ページ遷移時にどのような処理が行われるか、図があるとわかりやすいのですが自分で作るのが面倒なので、またあのページの”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に変換するparseLocationmatchersを定義しましょう。このパース関数はUpdate.elmMain.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 〜 施設個別ページ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です