Elmはシンプルで素晴らしんだけど、ドキュメントが弱い気がします。このブログでは、初心者の私がいろいろなソースを見つけて備忘録を付けています。そこで他のJavaScriptライブラリのようにRouterを使いたいと思い、とりあえずNavigationにたどり着きました。
http://package.elm-lang.org/packages/elm-lang/navigation/latest/Navigation
通常のHtmlではリンク(aタグ)をクリックしたときに、通常のように別ページを読み込むためのリクエストをサーバに送り、別ページに遷移します。Navigationはこの動作を、Msgを発行してupdate関数を呼ぶように変更します。以下がサンプルです。
https://github.com/elm-lang/navigation/tree/master/examples
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Navigation
main =
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
-- MODEL
type alias Model =
{ history : List Navigation.Location
}
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
( Model [ location ]
, Cmd.none
)
-- UPDATE
type Msg
= UrlChange Navigation.Location
{- We are just storing the location in our history in this example, but
normally, you would use a package like evancz/url-parser to parse the path
or hash into nicely structured Elm values.
<http://package.elm-lang.org/packages/evancz/url-parser/latest>
-}
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
UrlChange location ->
( { model | history = location :: model.history }
, Cmd.none
)
-- VIEW
view : Model -> Html msg
view model =
div []
[ h1 [] [ text "Pages" ]
, ul [] (List.map viewLink [ "bears", "cats", "dogs", "elephants", "fish" ])
, h1 [] [ text "History" ]
, ul [] (List.map viewLocation model.history)
]
viewLink : String -> Html msg
viewLink name =
li [] [ a [ href ("#" ++ name) ] [ text name ] ]
viewLocation : Navigation.Location -> Html msg
viewLocation location =
li [] [ text (location.pathname ++ location.hash) ]
まず次の宣言ですが、これで画面上でURLリンクをクリックしたときに UrlChange Navigation.Location のMsgを発行してくれるようになります。
main =
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
念のためにprogram関数の型をあげておきます。
program
: (Location -> msg)
-> { init : Location -> (model, Cmd msg), update : msg -> model -> (model, Cmd msg), view : model -> Html msg, subscriptions : model -> Sub msg }
-> Program Never model msg
Msgを受け取ったupdateはmodelのリストにlocationを追加します。追加のコードは以下です。
{ model | history = location :: model.history }
これは見易いようにカッコを付けると以下のようになります。
{ model | history = (location :: model.history) }
このプログラムを実行すると"bears", "cats", "dogs"などのリンクが表示されますので、それらをクリックすると、以下のようにlocation.pathname ++ location.hashを表示するものです。例えば、path="/examples/Example.elm"、hash="#dogs"となっています。
History
/examples/Example.elm#dogs
/examples/Example.elm#cats
/examples/Example.elm#bears
/examples/Example.elm
プログラム中のコメントは次のように言っています。つまり、ここではlocationはただ単にそのままリストに蓄えていっているけれども、普通はpathnameやhashの文字列をparseして、Elmの構造化された値に変換します。evancz/url-parserというElm作者の作ったパッケージが使われます。