Elm 0.18で作るTodoアプリ(1)

# はじめに
Webアプリのフレームワークを調査対象としてelmを選択しました。

特徴を把握するために、他のフレームワークでよく作られている、TodoアプリをWebで探したのですが、初心者に適切なサンプルが見つかりませんでした。

難易度が高かったり、elmのバージョンが古くて0.18では動かなかったりしたので、0.18の環境で自分で作ることにしました。

初めてelmを学ぶ方の参考になれば幸いです。

私自身、初めてのelmでいろいろと参考にしながら作成しているため、本筋で関係ない(使われない)ゴミデータが含まれていることもありますがご了承ください。
最終的にはゴミデータのない実装を目指し、少しずつ拡張していく予定です。

# 実行環境
* OS：CentOS 7.3
* Node：v6.11.3
* npm: v3.10.10
* nodebrew: v0.9.7
* elm: v0.18

elmの導入時にnpmでつまずいたので、その時の記事は下記を参照ください。
[npmのプロキシ設定の優先順位](https://qiita.com/tomluck/items/85376a204811bee10921)

# 全体設計
言語は違いますがReact.jsの下記の記事を参考にしました。
[ステップバイステップReact.jsで作るTodoアプリ](https://qiita.com/zuzu/items/73ec0321fac5c76e13c5)

TodoCreatorに関しては今回は扱わず、次回以降に扱うことになると思います。

# 今回のテーマ
固定値のTodoをTodoリストへ追加できるようにする

# ファイル構成
- Main.elm：大元のプログラム。基本的には配下のモジュールへ委譲するのみ。
- TodoList.elm：Todoのリスト管理を行う

# 実装

## Todolist.elmの作成
- moduleの宣言とimport関連

```hs

module TodoList exposing (..)

import Html exposing (..)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)
```

- モデルの定義

ここでは、ToDo型を定義し、そのListを保持するものをModelとします。
ToDoを追加するのでAddNewというMsgを定義します。

```hs
-- model
type alias ToDo = 
    { count : Int
    , item : String
    }

type alias Model = 
    { todoList : List ToDo
    }

initialModel : Model
initialModel = 
    { todoList = 
        [ ToDo 1 "item1" 
        , ToDo 2 "item2"
        ]
    }

type Msg
    = NoOp
    | AddNew ToDo
```

- updateの定義

ここでは、AddNewの引数でtodoをもらい、それをtodoListへ追加することにしました。

```hs

-- update
update : Msg -> ToDo -> Model -> ( Model, Cmd Msg )
update message todo model =
    case message of
        NoOp ->
            model ! []

        AddNew todo -> 
            ( { model | todoList = model.todoList ++ [todo] }, Cmd.none )
```

- viewの定義

updateButtonの定義でonClickが来たら(ToDo 4 "item4")という固定値をリストに追加します。
これで、リストに追加できることが確認できると思います。

```hs

-- view
view : Model -> Html Msg
view model = 
    div []
        [ viewList model.todoList
        ]

viewList : List ToDo -> Html Msg
viewList models = 
    div [ class "p2" ]
    [ viewItems models
    , updateButton models
    ]

viewItems : List ToDo -> Html Msg
viewItems models = 
    ul [] (List.map viewItem models)

viewItem : ToDo -> Html Msg
viewItem model = 
    li [] [
        text model.item
    ]

updateButton : List ToDo -> Html Msg
updateButton models = 
    div [] 
        [ button [ onClick (AddNew (ToDo 4 "item4")) ] [ text "Click" ] ]
```



## Main.elmの作成

Mainは配下のモジュールに委譲するところがポイントになると思います。
親子関係のやりとりなどは下記のサイトが参考になりました。
[Elmチュートリアル　合成](https://www.elm-tutorial.org/jp/02-elm-arch/06-composing.html)

今回の例ではupdateやviewで処理を配下のTodoListへ委譲しています。
また、TodolistのupdateでAddNewが引数を必要としているため、Mainから委譲する時にTodoList.ToDoを渡していますが、ダミーデータです。実際はTodolist.elmにあるupdateButtonのAddNewの引数が使われます。

子の属性を親が使っていて気持ち悪いのですが、次回以降に直します。

```hs

module Main exposing (..)

import Html exposing (Html, program)
import TodoList

main : Program Never AppModel Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

-- model
type alias AppModel =
    { todoListModel : TodoList.Model
    }

initialModel : AppModel
initialModel = 
    { todoListModel = TodoList.initialModel
    }

init : ( AppModel, Cmd Msg)
init = 
    ( initialModel, Cmd.none)

type Msg
    = TodoListMsg TodoList.Msg

-- update
update : Msg -> AppModel -> ( AppModel, Cmd Msg )
update message model = 
    case message of
        TodoListMsg subMsg ->
            let
                ( updatedTodoListModel, todoListCmd ) =
                    TodoList.update subMsg (TodoList.ToDo 0 "dummy") model.todoListModel
            in
                ( { model | todoListModel = updatedTodoListModel }, Cmd.map TodoListMsg todoListCmd )

-- subscription
subscriptions : AppModel -> Sub Msg
subscriptions model =
    Sub.none

-- view
view : AppModel -> Html Msg
view model =
    Html.div []
        [ Html.map TodoListMsg (TodoList.view model.todoListModel) 
        ]
```

# make
オプション(--debug)を付けると状態変化が見られて便利です。
```
$ elm-make Main.elm --output index.html --debug
```

# 実行結果
作成したindex.htmlをブラウザで見ます。
clickボタンを押下するごとにitem4のタスクが増えていくことが分かると思います。
![FF_elm_study1.png](https://qiita-image-store.s3.amazonaws.com/0/129853/59fd0a21-c59e-3ae8-9e44-160abc9bd348.png)

# おわりに
今回はTodoの固定値をリストへ追加するサンプルを作成しました。
次回はテキストボックスで入力した値をリストへ追加するように拡張しようと思います。
次回：[Elm 0.18で作るTodoアプリ(2)](https://qiita.com/tomluck/items/ec95df77fb54c9d54275)