elm

elmでwebアプリ作成12 〜 施設編集機能

前回、施設編集ページを作りましたが、まだオープンとクローズ時間の欄しかないので、ほかの情報も編集できるようにビューを作ります。

また同時に、各フィールドに入力された時点でモデルをアップデートするようにしておきます。その時点でデータベースに反映することもできますが、DBアクセスは編集が全て終わってから一度だけにしたいので、ここでは一時的にモデルが更新されるだけです。デバッグコードを入れておくので、入力するたびにコンソールログに結果が表示されます。最後に保存ボタンを置いて、それを押したときにデータベースに反映させる仕組みにしましょう。

先ほどgithubのリポジトリを作ったので、そこからコード全体も見れます。

src/Facilities/SingleEdit.elmの編集

オープン、クローズ、郵便番号、住所、ウェブサイトURL、説明欄の編集ができるようにします。またモデルのアップデートのため、inputタグにvalueonInputを設定しておきます。Msgs.Change...は、src/Msgs.elmで定義します。以下、変更部分のみです。今回はgithubへの最初のコミットなので、変更箇所がわかりませんが、次回からはコミット単位で記事を書いて行くつもりなので、githubで変更箇所を確認すれば正確に追えるようなります。

-- いくつかインポート関数が増えた
import Html exposing (button, div, h1, Html, input, p, text, textarea)
import Html.Attributes exposing (class, cols, placeholder, name, rows, size, type_, value)
import Html.Events exposing (onClick, onInput)

-- 編集フォーム
-- オープン・クローズのところにもonInputでのメッセージを追加
editForm : Facility -> Html Msg
editForm model =
    let _ = Debug.log "model:" model in
    div []
        [ div [ class "col col-8 px1"]
            [ p []
                [ text "Opening time: "
                , input [ type_ "time", value model.opening.open, onInput (Msgs.ChangeOpenTime model) ] []
                , text " - "
                , input [ type_ "time", value model.opening.close, onInput (Msgs.ChangeCloseTime model) ] []
                ]
            , p []
                [ text "Postal code (Zip code): "
                , input [ type_ "text", value model.postcode, onInput (Msgs.ChangePostCode model) ] []
                ]
            , p []
                [ text "Address: "
                , input [ type_ "text", size 100, value model.address, onInput (Msgs.ChangeAddress model) ] []
                ] -- サイズをレスポンシブにしたい
            , p []
                [ text "URL: "
                , input [ type_ "url", size 100, value model.web_site, onInput (Msgs.ChangeWebSite model) ] []
                ]
            , p []
                [ text "Description: "
                , textarea [ rows 10, cols 100, value model.description, onInput (Msgs.ChangeDescription model)] []
                ]
            , button [] [ text "Submit"]
            ]
        ]

src/Msgs.elmの編集

各フィールドの編集時に送信されるメッセージを定義します。どの施設の情報を編集するか(Facility)と、その値(String)をメッセージと一緒に送ります。

type Msg
    = OnFetchFacilities (WebData (List Facility))
    | OnLocationChange Location
    | ChangeOpenTime Facility String
    | ChangeCloseTime Facility String
    | ChangeAddress Facility String
    | ChangePostCode Facility String
    | ChangeWebSite Facility String
    | ChangeDescription Facility String

src/Update.elmの編集

各メッセージに対応するアップデート処理を追加します。どのフィールドを変更しても、

  1. 該当するFacilityの該当箇所の値を更新
  2. 更新したFacilityをモデルに反映

という流れは一緒なので、updataFacility関数を作ってモデルに反映する部分を共通化しました。以下全部。

module Update exposing (..)

import Models exposing (Model, Facility)
import Msgs exposing (Msg(..))
import RemoteData
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 )
        Msgs.ChangeOpenTime facility time ->
            let
                updatedOpening = { open = time, close = facility.opening.close}
                updatedFacility = { facility | opening = updatedOpening }
            in
                ( updateFacility model updatedFacility, Cmd.none )
        Msgs.ChangeCloseTime facility time ->
            let
                updatedOpening = { open = facility.opening.open, close = time}
                updatedFacility = { facility | opening = updatedOpening }
            in
                ( updateFacility model updatedFacility, Cmd.none )
        Msgs.ChangeAddress facility newAddress ->
            let
                updatedFacility = { facility | address = newAddress }
            in
                ( updateFacility model updatedFacility, Cmd.none )
        Msgs.ChangePostCode facility newPostCode ->
            let
                updatedFacility = { facility | postcode = newPostCode }
            in
                ( updateFacility model updatedFacility, Cmd.none )
        Msgs.ChangeWebSite facility newWebSite ->
            let
                updatedFacility = { facility | web_site = newWebSite }
            in
                ( updateFacility model updatedFacility, Cmd.none )
        Msgs.ChangeDescription facility newDescription ->
            let
                updatedFacility = { facility | description = newDescription }
            in
                ( updateFacility model updatedFacility, Cmd.none )

        --Msgs.ChangeOpeningTime facility ->
        --    --let
        --    --    updatedFacility = { facility | opening = openingTime }
        --    --in
        --    ( updateFacility model facility, Cmd.none)

updateFacility : Model -> Facility -> Model
updateFacility model updatedFacility =
    let
        replace currentFacility =
            if currentFacility.id == updatedFacility.id then
                updatedFacility
            else
                currentFacility
        updateFacilities facilities = List.map replace facilities
        updatedFacilities = RemoteData.map updateFacilities model.facilities
    in
        { model | facilities = updatedFacilities }

yarn startしてlocalhost:3000で確認してみましょう。ブラウザのコンソールログを確認すると、フィールドに入力するたびにモデルがアップデートされているのがわかります。デバッグコードはsrc/Facilities/SingleEdit.elm30行目に入れています。ただ、冒頭にも書きましたが、ここでは画面上で一時的に変更している状態なのでデータベースには反映されません。リロードすると元に戻ります。

次回は、これをデータベースに反映させる処理を作ります。

コメントを残す

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