Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part9 ~最終回~

#前回のパート
前回はtodo削除機能の実装を行いました
今回は残す最後の機能として、todoの更新機能の実装をやっていきます
今回が最後のパートになります
前回のパートはこちら→[Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part8](https://qiita.com/Kyu-Taro/items/f97b21cc1c1adbeb182e)

#Laravel側の実装
todoの更新に使うのは`TodoController.php`の`update()`アクションになります
`update()`アクションは`/todo{id}`に対してPUTリクエストで呼び出されます

それでは`TodoController.php`を開き`update()`アクションに下記を追加してください

```TodoController.php
public function update(Request $request, $id)
{
    $todo = Todo::find($id);
    $todo->text = $request->text;
    $todo->save();

    return response('', 200);
}
```
引数の$idを受け取ってtodosテーブルからそのidに該当するレコードを所得して
`$request->text`で送られてきたデーターに更新しています
Laravel側の実装はこれで終了です

#Vue側の実装
`Todo.vue`を開き下記のように変更と追加をしてください

```Todo.vue
<template>
    <div>
        <Header />
        <div class="main-container">
            {{ user.name }}のTodoリスト

            <v-text-field v-model="text" label="todo" required></v-text-field>
            <v-btn class="btn" @click="create">登録</v-btn>

            <template v-for="(item, index) in items">
                <v-card max-width="450" class="mx-auto" style="marign-top: 10px" :key="item.id">
                    <v-list three-line>
                        <v-list-item :key="item.id">
                            <v-list-item-content>
                                <input type="text" v-model="item.text" @keydown.enter="unforcus" @blur="update(item.id, item.text)">    //追加
                                <v-btn small @click="del(item.id, index)">完了</v-btn>
                            </v-list-item-content>
                        </v-list-item>
                    </v-list>
                </v-card>
            </template>
        </div>

    </div>
</template>

<script>
    import Header from './Header';
    import axios from 'axios';

    export default {
        components: {
            Header
        },
        metaInfo: {
            title: 'Todo',
            htmlAttrs: {
                lang: 'ja'
            }
        },
        created () {
            const user = this.$store.getters['auth/user'];
            if (user === null) {
                this.$router.push('/login');
            }

            axios.get('/api/todo')
            .then((res) => {
                this.items = res.data;
            });
        },
        computed: {
            user() {
                return this.$store.getters['auth/user'];
            }
        },
        data () {
            return {
                items: null,
                text: ''
            }
        },
        methods: {
            async create() {
                await axios.post('/api/todo', { text: this.text });

                axios.get('/api/todo')
                .then((res) => {
                    const newItem = res.data.slice(-1)[0];
                    this.items.push(newItem);
                })

                this.text = '';
            },
            async del(id, index) {
                await axios.delete('/api/todo/' + id);
                this.items.splice(index,1);
            },
            async update(id, text) {    //追加
                await axios.put('/api/todo/' + id, { text: text });

                let itemsIndex = '';
                this.items.map((value,index) => {
                    if (value.id === id) {
                        itemsIndex = index;
                    }
                });

                this.items[itemsIndex].text = text;
            },
            unforcus() {    //追加
                if (event.keyCode !== 13) {
                    return
                }

                document.activeElement.blur();
            }
        }
    }
</script>

<style>
    .main-container {
        width: 500px;
        margin: auto;
    }
    .btn {
        margin-bottom: 20px;
    }
</style>
```

3箇所の追加を行いました
まずこの部分ですが 
`<input type="text" v-model="item.text" @keydown.enter="unforcus" @blur="update(item.id, itme.text)">`
input要素に内容が書き込まれEnterキーを押すことで`unforcus`メソッドが発火するようにしました
それによりフォームに当たっているフォーカスEnterを押すことではすずれるようになっています

```Todo.vue 
            unforcus(id, text) {   
                if (event.keyCode !== 13) {
                    return
                }
                document.activeElement.blur();
            }
```
if文の箇所ですが、この部分がなければtodoの変更でinputに日本語の入力をした際に
変換などでEnterキーを押すとそれで発火してしまいます
そのためif文での処理を追加しています
日本語入力の際の変換でのEnterをKeyCodewを299を返します
日本語入力の変換でのEnterではない(今回の場合はtodoの変更のEnter)の場合はKeyCodeを13を返します
本来発火させたいのは、後者のKeyCode13の場合です
なので`unforcus`メソッドの最初でこのEnterキーは13なのかどうかをチェックしています
この処理がなければ、Enterを押すたびに処理が走ってしまうため入力途中のものなどが登録されることになりますので注意してください

また、最後の1行`document.activeElement.blur()`こちらでフォームのフォーカスを外しています

次にこちらのメソッドです

```Todo.vue
            async update(id, text) {

                await axios.put('/api/todo/' + id, { text: text });

                let itemsIndex = '';
                this.items.map((value,index) => {
                    if (value.id === id) {
                        itemsIndex = index;
                    }
                });

                this.items[itemsIndex].text = text;
            },

```
こちらはフォーカスが外れることで発火するよになっています
Enterキーを押すことで、フォーカスが外れその後`update()`メソッドが発火し登録処理を行うと言う形です
また入力中にEnterを押されなく、クリックなどでフォーカスが外れた際にも登録処理が走るようになっています

まずLaravel側の`/todo`に対してtodoのidと変更内容をPUTでリクエストしています
これで、先ほど実装したLaravel側での`TodoController.php`の`update()`アクションを呼び出すことができます

中の処理ですが、`this.items.map()`を利用し
itemsの中身のidと変更のあったidが一致するものを調べ、一致したもののindex番号を変数で保持しています
その後、`this.items[itemsIndex].text - text`でitemsの該当するオブジェクトに
変更内容に書き換えVueに反映するようにしています

ここまでの実装で、todoの更新ができるようになっています
表示されているtodoをクリックし、違うものに書き換えてEnterキーを入力してみてください
正常に実装できていれば、todoが編集され画面に出力されているかと思います

以上で本記事での全ての機能の実装が終わりました
会員登録、ログイン、ログアウト、todoの一覧表示、todoの新規作成、todoの削除、todoの更新
この機能を組み合わせればTodoリスト意外の開発でも同じ要領で色々な物が作れるかと思います


#最後に
今回は最後のパートとしてtodoの更新機能の実装を行いました
ここまでの9パート最後まで読んでいただきありがとうございました
少しでも、学習者の役に立てればと思いこの記事を作成しました
また、本記事では未熟である私自身が書いた記事のため
まだまだ、改善点やリファクタリング等もできるかと思いますので
このチュートリアルを進めて頂いた方々個人で取り組んで頂ければと思います。
また、間違った点や気になった点アドバイスなど御座いましたら
是非コメント頂ければと思っておりま
ありがとうございました。