SIer だけど技術やりたいブログ

Vuejs <button type="reset"> の併用はアブナイ

javascript vuejs html5

<button type="reset">とは?

HTMLのButtonのひとつで、Formを自動でクリアできる。
参考: button 要素 - HTML | MDN

<!doctype html>
<html>
  <body>
    <form>
      <input type="text" placeholder="username" />
      <input type="password" placeholder="password" />
      <button type="reset">reset</button>
    </form>
  </body>
</html>

resetボタンをクリックするとFormが自動でクリアされて、地味にうれしい。

課題

Vuejsと併用すると、resetボタン押下時に見ため上はクリアされたようにみえるが、Vuejsで管理しているdataプロパティの値はクリアされない。見た目とvuejs上のデータが乖離する。

<template>
  <form @submit.prevent="save">
    <p>
      <input type="text" v-model="text" />
    </p>
    <p>
      <textarea v-model="textarea" />
    </p>
    <p>
      <input type="checkbox" v-model="checked" />
    </p>
    <p>
      <input type="radio" id="one" value="one" v-model="radio" />
      <input type="radio" id="two" value="two" v-model="radio" />
    </p>
    <p>
      <select v-model="select">
        <option disabled value="" selected>please select</option>
        <option>A</option>
        <option>B</option>
        <option>C</option>
      </select>
    </p>
    <button type="reset">reset</button>
    <button type="submit">save</button>
  </form>
</template>

<script>
export default {
  name: 'Form',
  data () {
    return {
      text: '',
      checked: false,
      textarea: '',
      radio: '',
      select: ''
    }
  },
  methods: {
    save: function () {
      console.log(`save text: ${this.text} textarea: ${this.textarea} checked: ${this.checked} radio: ${this.radio} select: ${this.select}`)
    }
  }
}
</script>

以下のように、resetボタンを押したあとも、dataプロパティの値がそのまま残っている。

解決方法

<button type="reset">を利用しない。 フィールドをクリアしたければ、自分でハンドラを設定してdataプロパティをリセットする

<template>
...
    <button @click="clear" type="button">reset</button>
...
</template>

<script>
...
methods: {
    ...
  clear: function () {
    this.text = ''
    this.checked = false
    this.textarea = ''
    this.radio = ''
    this.select = ''
  }
}
</script>

以下のように、resetボタンを押したときに、dataプロパティもリセットされている。

dataプロパティの初期値を丸ごと設定する場合は、以下のようにも書ける。

<script>
...
// ここを再利用する
data () {
  return {
    text: '',
    checked: false,
    textarea: '',
    radio: '',
    select: ''
  }
},
methods: {
    ...
    clear: function () {
      Object.assign(this.$data, this.$options.data.call(this))
    }
  }
}
</script>

参考: stack overflow

補足情報

Vuetifyというフレームワークを利用していた場合、こんな感じで組み込みのFormコンポーネントをrefで参照してreset()メソッドを呼び出せば、nullで初期化してくれる。
参考: Vuetify issue

<template>
...
      <v-form ref="form">
...
</template>

<script>
...
    clear: function () {
      this.$refs.form.reset()
    }
...
</script>

リッチなUIフレームワークを利用すると、上記のような恩恵も受けられる。