TODOリストを作る部 その3

nekoroll.hatenablog.com
の続き
編集→更新ができるようにした
ellie-app.com

やること

  • [x] ListでTODOリストを保持する
  • [x] ListをHTMLに吐き出す
  • [x] inputに入力した値をbuttonを押すことでリストに追加
  • [x] TODO横に削除ボタンを作成、押したら消せるように
  • [x] TODOをダブルクリックでinput化して更新できるように
  • [ ] localstorageに保存できるようにする
  • [ ] 見た目オシャンティーにする

やったこと

TODOダブルクリックでinputタグに変化させる

編集中フラグをTODOに持たせる

type alias Todo =
    { id : Int
    , todo : String
    , editting : Bool
    }

デフォルトFalseでダブルクリック時にTrueになる

MsgEdit追加

type Msg
    | Edit Int Bool

Editid指定でフラグを更新する想定なのでInt Bool

id指定でフラグを更新する関数を実装

setEdittingByIndex : List Todo -> Int -> Bool -> List Todo
setEdittingByIndex todoList id isEditting =
    List.map
        (\todo ->
            if todo.id == id then
                { todo | editting = isEditting }

            else
                todo
        )
        todoList

List.mapで全てのTODOに対して
指定IDのTODOの編集フラグを更新する無名関数
を適用して新しいTODOリストを作成
(これ削除のときも似たような処理書いたな…)

filterByIndex : List Todo -> Int -> List Todo
filterByIndex todoList id =
    List.filter (\todo -> todo.id /= id) todoList

編集中フラグを判定しHtmlを返す処理を実装

switchTodoElement : Bool -> Todo -> List (Html Msg)
switchTodoElement isEditting todo =
    if isEditting then
        [ input
            [ type_ "text"
            , value todo.todo
            , onBlur (Edit todo.id False)
            ]
            []
        , button [ onClick (Edit todo.id False) ] [ text "update" ]
        ]

    else
        [ text (todo.todo ++ " ")
        , button [ onClick (Delete todo.id) ] [ text "delete" ]
        ]

TrueならTODOを編集するinputタグと更新を行うbuttonを作成
Falseならtextと削除を行うbuttonを作成

フォーカスが離れた時かUpdateボタンを押した際に編集モードを終了する

TODOリスト作成関数に手を加える

showTodo : Todo -> Html Msg
showTodo todo =
    li [ onDoubleClick (Edit todo.id True) ]
        (switchTodoElement todo.editting todo)

lionDoubleClickEditを呼ぶよう修正
edittingによって編集可能なTODOと表示するだけのTODOを出し分ける

Edit``Variantの処理を実装

Edit id isEditting ->
            { model | todoList = setEdittingByIndex model.todoList id isEditting }

フラグ編集対象のTODOのidと編集フラグisEdittingを受け取って
対象のTODOの編集フラグを更新する

TODOを更新できるようにする

MsgUpdate追加

type Msg
    = Add
    | Update Int String

TODO更新処理実装

updateByIndex : List Todo -> Int -> String -> List Todo
updateByIndex todoList id newTodo =
    List.map
        (\todo ->
            if todo.id == id then
                { todo | todo = newTodo }

            else
                todo
        )
        todoList

List.mapで全てのTODOに対して
指定IDのTODOのTODOを更新する無名関数
を適用して新しいTODOリストを作成
(これ編集の時もry)

Update``Variantの処理を実装

        Update id newTodo ->
            { model | todoList = updateByIndex model.todoList id newTodo }

フラグ編集対象のTODOのidと更新後のTODOnewTodoを受け取って
対象のTODOを更新する

viewを修正

switchTodoElement : Bool -> Todo -> List (Html Msg)
switchTodoElement isEditting todo =
    if isEditting then
        [ input
            [ type_ "text"
            , value todo.todo
            , onInput (Update todo.id)
            , onBlur (Edit todo.id False)
            ]
            []
        , button [ onClick (Edit todo.id False) ] [ text "update" ]
        ]

    else
        [ text (todo.todo ++ " ")
        , button [ onClick (Delete todo.id) ] [ text "delete" ]
        ]

input状態のTODOにonInput (Update todo.id)を追加

これでTODOの編集、更新ができるようになった

まとめ

  • リスト操作ちょっと慣れてきた
    List.map使って処理できるようになった
    ただ無駄が凄いあるので、関数として切り出せると思う
  • 自分のやりたいことを愚直に書いていくだけで処理が出来上がる
  • 基本的な流れは掴めた気がする

今後

  • localstorageに保存するようにする
    多分portsが学べるはず
  • デザイン適用する
    CSS周り学べるはず
  • Ellieに全部乗せてるのでGithubにも上げとく
    ついでにローカル開発環境も整える

TODOアプリ作り終わったら次はこのゲーム作る
f:id:nekorollykk:20200830224918p:plain
(モヤさまで見て久々にやりたくなった)