ElmでCRUDを作る - 其のD

「ElmでCRUDを作る」最後です。
前回までに実装済みの部分については説明を省略してますので、そちらについては過去記事を参照お願いします。

[ElmでCRUDを作る - 其のR](https://qiita.com/akkey2475/items/768922a14174f26ec1dc)

[ElmでCRUDを作る - 其のC ①](https://qiita.com/akkey2475/items/a256ae33449e06d0d370)

[ElmでCRUDを作る - 其のC ②](https://qiita.com/akkey2475/items/32cdc207df94d7135cc3)

ElmでCRUDを作る - 其のD (この記事)

# 今回作ったもの

TODOリストの続きです。
今回は最後のD(Delete)を実装します。
リストのアイテム横の「×」ボタンをクリックするとリストからアイテムが削除されるようにします。

# 完成品

完成品こちらです。ここ([Try Elm!](https://elm-lang.org/try))で貼り付けて動作を試せます。

```elm
import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
 
 
-- MAIN

main =
  Browser.sandbox
    { init = init
    , update = update
    , view = view
    }
 
 
-- MODEL

type alias Model =
  { inputText : String
  , list : List String
  }
 
init : Model
init = Model "" []
 
 
-- UPDATE

type Msg
  = SetText String
  | AddItem
  | DeleteItem Int
 
update : Msg -> Model -> Model
update msg model =
  case msg of
    SetText inputText ->
      { model | inputText = inputText }
 
    AddItem ->
      { model | list = model.list ++ [model.inputText] }
 
    DeleteItem index ->
      { model | list = ( List.take index model.list ) ++ ( List.drop ( index + 1 ) model.list ) }
 
 
-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ input [ onInput SetText ] []
    , button [ onClick AddItem ] [ text "Add" ]
    , makeList model.list
    ]

 
-- ユーザー定義関数

makeList : List String -> Html Msg
makeList list =
  ul [] ( List.indexedMap makeListItem list )
 
makeListItem : Int -> String -> Html Msg
makeListItem index itemText =
  li []
    [ span [] [ text itemText ]
    , button [ onClick ( DeleteItem index ) ] [ text "×" ]
    ]
```

# 解説

## モジュール読み込み

ここは変更ないので割愛です。

## メイン関数

ここも同じく割愛。

## モデルの定義と初期化

ここも変更なしです。

## 更新処理の定義

```elm
type Msg
  = SetText String
  | AddItem
  | DeleteItem Int
```

今回メッセージにはアイテム削除用のバリアント `DeleteItem Int` を追加しました。
DeleteItemの持つ値にはアイテムの番号を表す数値が入ります。

```elm
update : Msg -> Model -> Model
update msg model =
  case msg of
    SetText inputText ->
      { model | inputText = inputText }

    AddItem ->
      { model | list = model.list ++ [model.inputText] }

    DeleteItem index ->
      { model | list = ( List.take index model.list ) ++ ( List.drop ( index + 1 ) model.list ) }
```

DeleteItemでの処理内容を追加で定義しています。
DeleteItemでは、indexの値を元にリストからアイテムを削除します。
Elmでは直接リストの特定位置の値を削除する関数がないので、リストのindexの位置より前のリストとindexの位置より後ろのリストを結合するという方法によってリストからアイテムを削除する処理を実現します。
List.takeがリストの前方を取得する関数、List.dropがリストの後方を取得する関数です。

List.take、List.dropの詳細はこちらです。
使い方はHaskellのtake,dropと全く同じなので、下の記事も参考になります。というかこっちの方がわかりやすい。

[List - core 1.0.4 - Elm Packages (take, drop)](https://package.elm-lang.org/packages/elm/core/latest/List#take)　※英語なので翻訳して読んでください。

[Haskell個人メモ :: 1.基本 (take, drop)](https://qiita.com/YusukeHosonuma/items/41ad9346b6e3a4d3789c#take--drop)

## ページ描画処理の定義

ここは前回と同じです。
削除に関する部分はユーザー定義関数の方で追加しています。

## ユーザー定義関数

```elm
makeList : List String -> Html Msg
makeList list =
  ul [] ( List.indexedMap makeListItem list )
```

一瞬変わっていないように見えますが、よくみると前回まで `List.map` だったのが `List.indexedMap` に変わっています。
これによって、 `makeListItem` にリストの文字列だけでなくインデックスも一緒に渡されることになります。

```elm
makeListItem : Int -> String -> Html Msg
makeListItem index itemText =
  li []
    [ span [] [ text itemText ]
    , button [ onClick ( DeleteItem index ) ] [ text "×" ]
    ]
```

makeListItemにはさっき説明したように `index` という引数が増えています。
また、中身にはアイテムを削除するためのボタンを追加しています。 `button [ onClick ( DeleteItem index ) ] [ text "×" ]` の部分です。
"x" というボタンが表示され、クリック時(onClick)にDeleteItemバリアントが更新処理に送られます。
この時、DeleteItemの値として一緒に渡されるのがさっきのindexです。
indexによってリストのどのアイテムを削除すれば良いかが分かるようになります。

# まとめ

削除処理の流れは前回説明したリストへのアイテム追加の流れと似たような感じです。
"x"ボタンのクリック⇒モデル更新(リストからアイテム削除)⇒ページ再描画、という感じになります。
こんな感じでどんどん機能を追加していけばもっと高機能な処理が実現していけます。

編集機能(Update)については、実装できてないので続きはありません。これで終わりです。
編集機能を実装するにはどういう方法で編集させるかという問題もありますし結構難しそうだなと思ってます。
どちらかというと並べ替え機能の実装とかの方が比較的簡単にできそうな気がします。やりませんが笑

全体通してなるべくわかりやすい記事を心がけましたが、もしわかりにくいところがあったらコメントお願いします。
間違いの指摘もよろしくお願いします。