vee-validateでカスタムルール(どちらか選択)

## 概要
リストのどちらかのみを選択するルールを作成してみる。

## 実装方法
下記のやり方でうまくいったので、添付しておく。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Validation</title>
</head>
<body>

  <div id="app">
    <h1>Vee-Validate(独自ルール - どちらか選択)</h1>

    <div>
      <label>カテゴリー</label>
      <div :class="{'is-error': errors.has('category') }">
        <select name="category1" v-model="category1" >
          <option v-for="item in list1" :value="item.value">
            {{ item.label }}
          </option>
        </select>
        <select name="category2" v-model="category2" >
          <option v-for="item in list2" :value="item.value">
            {{ item.label }}
          </option>
        </select>
      </div>
      <div v-show="errors.has('category')">
        <p>{{ errors.first('category') }}</p>
      </div>
    </div>

    <button type="button" @click="submit">作成する</button>

    <div v-show="errors.has('notification')">
      <p>{{ errors.first('notification') }}</p>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>
  <script src="https://cdn.jsdelivr.net/npm/vee-validate@2.1.0-beta.9/dist/vee-validate.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vee-validate@2.1.0-beta.9/dist/locale/ja.js"></script>
  <script>
    Vue.use(VeeValidate);

    new Vue({
      el: '#app',
      // データ
      data: {
        category1: null,
        list1: [
          {label:'- 未選択 -', value:null},
          {label:'りんご', value:'apple'},
          {label:'いちご', value:'strawberry'},
          {label:'ぶどう', value:'grape'}
        ],
        category2: null,
        list2: [
          {label:'- 未選択 -', value:null},
          {label:'オクラ', value:'okra'},
          {label:'カブ', value:'turnip'},
          {label:'キャベツ', value:'cabbage'}
        ],
      },
      created() {
        // メッセージを日本語に設定する
        this.$validator.localize('ja');

        /**
         * 入力検証 (カテゴリー)
         *
         * ※ カテゴリ1/カテゴリ2のどちらかを必ず選択する
         * ※ 両方選択することはできない
         */
        this.$validator.extend('category', {
          current: null,
          getMessage(field) {
            if (!this.current.category1 && !this.current.category2) {
              return 'どちらか１つ選択してください';
            } else if (this.current.category1 && this.current.category2) {
              return '両方選択することはできません';
            }
          },
          validate(value) {
            this.current = value;
            if (!value.category1 && !value.category2) {
              return false;
            } else if (value.category1 && value.category2) {
              return false;
            }
            return true;
          }
        });
        this.$validator.attach({
          name: "category",
          alias: 'カテゴリー',
          rules: "category",
          getter: () => this.category
        });
      },
      computed: {
        category() {
          return {
            category1 : this.category1,
            category2 : this.category2
          };
        }
      },
      watch: {
        category(value) {
          this.$validator.validate('category', value);
        }
      },
      methods: {
        submit: function () {
          // お知らせメッセージを初期化
          this.$validator.errors.remove('notification');

          // バリデートの判定
          this.$validator.validateAll().then((result) => {

            if (result === false) {
              // 入力エラー
              this.$validator.errors.add({
                field: 'notification',
                msg: '入力エラーがあります...'
              });
              return false;
            }

            // 何かしらの処理...
            console.log(Math.random());
            const is_success = (Math.random() > 0.3);
            if (!is_success) {
              // お知らせメッセージをセットする
              this.$validator.errors.add({
                field: 'notification',
                msg: '処理に失敗しました...'
              });
              return false;
            }

            //エラーがなかった時の処理を下に記述
            alert('Submit OK.')
          });
        }
      }
    });
  </script>
</body>
</html>
```
## 実行結果
作成ボタンを押すと、エラーメッセージが表示されました。
![test.png](https://qiita-image-store.s3.amazonaws.com/0/142279/53a2ff5a-b421-af37-04d3-8c5bffaabf39.png)

## 参考サイト
- [VeeValidate - Custom Rules](https://baianat.github.io/vee-validate/guide/custom-rules.html#creating-a-custom-rule)
- [validateAll() not running on validations attached in child component](https://github.com/baianat/vee-validate/issues/974)
- [VeeValidateで複数のフィールドにバリデーションをかけるやり方](https://qiita.com/_Keitaro_/items/c06210d69f8c8382dfab)
- [Vee-validate : how to attach several validation rules after object constructed](https://stackoverflow.com/questions/50050515/vee-validate-how-to-attach-several-validation-rules-after-object-constructed)
- [VeeValidate を使って、vue.jsで簡単にバリデートしてみた](https://qiita.com/youdie/items/417ed2df1bcb6a60001c)