[VeeValidate]入力中にバリデータを動かさないようにする

Vue.jsでバリデータを書く時に [VeeValidate](https://logaretm.github.io/vee-validate/)を活用しています。

VeeValidateの発動タイミングを操作する上でハマった場面がありましたので備忘録として残します。
おそらくもっといい方法があると思うので教えていただきたいです！！


## 要件


要件は
- ユーザーが書き込みを行なっている間はエラーメッセージを表示しない
- 送信ボタンが押された時だけエラーメッセージを表示する
というものです。

![2020-09-11 17.51.52.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194935/3c450860-a7d9-6e8d-8495-ef84a305d54c.gif)

上記のgifですと、まだユーザーが記入を続けている（focus)されている間にエラーメッセージが表示されています。

こちらを要件通りに実装し直す必要がありました。

**元コード**

```form.vue
<template>
  <div class="wrapper">
    <h3>form</h3>
    <div>
      <validation-provider name="name" rules="required" v-slot="{ errors }">
        <div>
          <label>
            名前
            <input type="text" v-model="name" />
            <span class="error">{{ errors[0] }}</span>
          </label>
        </div>
      </validation-provider>
      <validation-provider name="email" rules="required" v-slot="{ errors }">
        <div>
          <label>
            メールアドレス
            <input type="text" v-model="email" />
            <span class="error">{{ errors[0] }}</span>
          </label>
        </div>
      </validation-provider>
    </div>
    <button @click="submit">送信</button>
  </div>
</template>

<script>
import { ValidationProvider, extend} from 'vee-validate';
import { required } from 'vee-validate/dist/rules';

extend('required', required);

export default {
  components: {
    ValidationProvider,
  },
  data() {
    return {
      name: '',
      email: ''
    }
  },
  methods: {
    submit() {
      alert('送信に成功しました');
    }
  }
}
</script>

<style scoped>
.wrapper {
  margin-left: 50px;
  margin-top: 50px;
}

.error {
  color: red;
}
</style>
```

## とりあえずフォーム送信時に動くようにしてみる

[handleSubmit](https://logaretm.github.io/vee-validate/guide/forms.html#validate-before-submit)を使って `送信ボタン`を押すとバリデータが動くようにしてみました。

```form.vue
<template>
  <div class="wrapper">
    <h3>form</h3>
    <validation-observer v-slot="{ handleSubmit }">
      <div>
        <validation-provider name="name" rules="required" v-slot="{ errors }">
          <div>
            <label>
              名前
              <input type="text" v-model="name" />
              <span class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
        <validation-provider name="email" rules="required" v-slot="{ errors }">
          <div>
            <label>
              メールアドレス
              <input type="text" v-model="email" />
              <span class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
      </div>
      <button @click="handleSubmit(submit)">送信</button>
    </validation-observer>
  </div>
</template>

<script>
import { ValidationProvider, ValidationObserver, extend} from 'vee-validate';
import { required } from 'vee-validate/dist/rules';

extend('required', required);

export default {
  components: {
    ValidationProvider,
    ValidationObserver
  },
  data() {
    return {
      name: '',
      email: ''
    }
  },
  methods: {
    submit() {
      alert('送信に成功しました');
    }
  }
}
</script>

<style scoped>
.wrapper {
  margin-left: 50px;
  margin-top: 50px;
}

.error {
  color: red;
}
</style>
```

![2020-09-11 18.06.58.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194935/077a56df-1415-67e2-7afc-b18facb17878.gif)


確かに送信ボタンを押した時にバリデータが動いてします。
しかし、`ユーザーが書き込みを行なっている間はエラーメッセージを表示しない`に対応ができていません。

## eventsを使ってみる

[イベントの無効化](https://vee-validate.logaretm.com/v2/guide/events.html#changing-events-per-field)や[こちら](https://github.com/logaretm/vee-validate/issues/1878)を参考にやってみたが変わらない...

一応実装コード

```form.vue
<template>
  <div class="wrapper">
    <h3>form</h3>
    <validation-observer v-slot="{ handleSubmit }">
      <div>
        <validation-provider name="name" rules="required" :events="[]" v-slot="{ errors }">
          <div>
            <label>
              名前
              <input type="text" v-model="name" />
              <span class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
        <validation-provider name="email" rules="required" v-slot="{ errors }">
          <div>
            <label>
              メールアドレス
              <input type="text" v-model="email" />
              <span class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
      </div>
      <button @click="handleSubmit(submit)">送信</button>
    </validation-observer>
  </div>
</template>

<script>
import { ValidationProvider, ValidationObserver, extend} from 'vee-validate';
import { required } from 'vee-validate/dist/rules';

extend('required', required);

export default {
  components: {
    ValidationProvider,
    ValidationObserver
  },
  data() {
    return {
      name: '',
      email: ''
    }
  },
  methods: {
    submit() {
      alert('送信に成功しました');
    }
  }
}
</script>

<style scoped>
.wrapper {
  margin-left: 50px;
  margin-top: 50px;
}

.error {
  color: red;
}
</style>
```

## 力技で対応

focusしているときはErrorを表示させないように `v-show`で制御しました。

```
<template>
  <div class="wrapper">
    <h3>form</h3>
    <validation-observer v-slot="{ handleSubmit }">
      <div>
        <validation-provider name="name" rules="required" v-slot="{ errors }">
          <div>
            <label>
              名前
              <input type="text" v-model="name" @focus="showNameError = false" />
              <span v-show="showNameError" class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
        <validation-provider name="email" rules="required" v-slot="{ errors }">
          <div>
            <label>
              メールアドレス
              <input type="text" v-model="email" @focus="showEmailError = false" />
              <span v-show="showEmailError" class="error">{{ errors[0] }}</span>
            </label>
          </div>
        </validation-provider>
      </div>
      <button @click="beforeHandleSubmit(handleSubmit(submit))">送信</button>
    </validation-observer>
  </div>
</template>

<script>
import { ValidationProvider, ValidationObserver, extend} from 'vee-validate';
import { required } from 'vee-validate/dist/rules';

extend('required', required);

export default {
  components: {
    ValidationProvider,
    ValidationObserver
  },
  data() {
    return {
      name: '',
      email: '',
      showNameError: false,
      showEmailError: false,
    }
  },
  methods: {
    submit() {
      alert('送信に成功しました');
    },
    beforeHandleSubmit(func) {
      this.showNameError = true;
      this.showEmailError = true;
      func().then;
    },
  }
}
</script>

<style scoped>
.wrapper {
  margin-left: 50px;
  margin-top: 50px;
}

.error {
  color: red;
}
</style>
```

![2020-09-11 18.35.42.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194935/d453bfb0-96c0-172b-c242-bc5002b520ee.gif)


一応要件は満たせましたが、
コードとしても煩雑になりますし、微妙な感じですね。。。。

もっといい方法がないか探してみたいと思います！！