VueでMaterializeのChipsを上手に使う方法

Materialize というCSSフレームワークにはさまざまな物が用意されています。
今回は `Chips` というものを Vue.js で上手に使う方法を紹介していきます。

## Chips を用意する
まずは、 `Chips` が画面に表示されるようにします。
今回は Vue を使うので、 Vue ファイルに書いていきます。

```vue:Test.vue
<template>
  <div class="chip">
    aaaaa
    <i class="close material-icons">close</i>
  </div>
</template>
```

すると、以下のような画面になります。
<img width="133" alt="スクリーンショット 2019-11-15 9.56.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425008/0d42c49e-6fac-6589-2deb-b9930811869d.png">
ここで「×」ボタンを押すと、フロントでは `aaaaa` という Chips は削除されますが、
ページを更新すると、また `aaaaa` は表示されてしまいます。

## Vue にて API からデータを取得・削除する
そこで、 vue ファイルに以下の記述を追加します。
（`axios` を使用していきます。）

```vue:Test.vue
<template>
  <div
    v-for="(test, index) in tests" :key="index"
    class="chip"
  >
    {{ test.title }}
    <i class="close material-icons">close</i>
  </div>
</template>

<script>
import axios from 'axios';

data: function () {
    return {
      tests: [],
    }
  },

  mounted: function () {
    this.fetchTests();
  },

  methods: {
    fetchTests: function () {
      axios
      .get('/api/tests')
      .then((res) => {
        for (var i = 0; i < res.data.tests.length; i++) {
          this.tests.push(res.data.tests[i]);
        }
      }, (error) => {
        console.log(error);
      });
    },

    deleteTest: function (test_id) {
      if ( confirm('投稿を削除しますか？') ) {
        axios
        .delete('/api/tests/' + test_id)
        .then((res) => {
          var test_title = res.data.test.title;
          M.toast({html: '「' + test_title + '」の情報を削除しました'});
        }, (error) => {
          console.log(error);
        });
      }
    },
  },
</script>
```

ここでは、 `api/tests` には `id` と `test_title` という情報が入っており、
それぞれを `v-for` でまわして取得しています。

上記の変更で、 `Chips` の「×」ボタンを押すことによって、
ページを更新したら、「×」ボタンを押した `Chips` は再度表示されることはなくなりました！

### 番外編（ `Chips` の詳細に飛ぶ）
`Chips` の「×」ボタン以外の場所を押したら、
データの詳細のようなものを表示するようにしていきます。

```vue:Test.vue
<template>
  <div
    v-for="(test, index) in tests" :key="index"
    v-on:click="setTestInfo(test.id)"
    class="chip"
  >
    {{ test.title }}
    <i class="close material-icons">close</i>
  </div>

  <div class="row" v-if="testInfoBool === true">
    <div class="col s12 m12">
      <div class="card amber darken-4">
        <div class="card-content white-text">
          <span class="card-title">
            {{ tesuInfo.id }}：{{ testInfo.title }}
          </span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

data: function () {
    return {
      tests: [],
      testInfo: {},
      bInfoBool: false,
    }
  },

  mounted: function () {
    this.fetchTests();
  },

  methods: {
    fetchTests: function () {
      axios
      .get('/api/tests')
      .then((res) => {
        for (var i = 0; i < res.data.tests.length; i++) {
          this.tests.push(res.data.tests[i]);
        }
      }, (error) => {
        console.log(error);
      });
    },

    setTestInfo: function (test_id) {
      axios
      .get('api/tests/' + test_id)
      .then((res) => {
        this.testInfo     = res.data.test;
        this.testInfoBool = true;
      }, (error) => {
          console.log(error);
      });
    },

    deleteTest: function (test_id) {
      if ( confirm('投稿を削除しますか？') ) {
        axios
        .delete('/api/tests/' + test_id)
        .then((res) => {
          var test_title = res.data.test.title;
          M.toast({html: '「' + test_title + '」の情報を削除しました'});
        }, (error) => {
          console.log(error);
        });
      }
    },
  },
</script>
```

現状だと、上記の記述を追加したとしても「×」ボタンの箇所を押したら、
`setTestInfo` と `deleteTest` の２つが反応してしまします。

そこで、 `<template>` 内の記述を変更していきます。

```vue:Test.vue
<template>
  <div
    v-for="(test, index) in tests" :key="index"
    v-on:click.self="setTestInfo(test.id)"
    class="chip"
  >
    {{ test.title }}
    <i class="close material-icons">close</i>
  </div>
</template>

<script>

・・・
```

v-on:click の後に `.self`を追加するだけで、
要素自身がクリックされたときだけ、ハンドラが呼び出されるようになります。

### 参考
[Chips - Materialize](https://materializecss.com/chips.html)
[イベントハンドリング — Vue.js](https://jp.vuejs.org/v2/guide/events.html#%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E4%BF%AE%E9%A3%BE%E5%AD%90)