Vuejs formをサブミットするときのポイント

SPAの場合はformタグに任せてデータをサブミットすることは稀で、通常は自身で定義したハンドラを呼び出してAjax通信を行うことが多い。

課題

以下のように<button type="submit" @click="exec">を使ってボタン押下時のハンドラを実行するのは危ない。

<template>
  <form>
    <input type="text" placeholder="username" />
    <input type="text" placeholder="password" />
    <button type="submit" @click="exec">submit</button>
  </form>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    exec: function () {
      // 本来はajax通信をする
      console.log('exec')
    }
  }
}
</script>

上記の記述だと、テキストフィールドでEnterを押した場合に一瞬コンソールログが出力され、自画面に遷移してしまう。

f:id:kimulla:20191201140525g:plain

参考 HTML 5.2: 4.10. Forms
参考 HTML 5.2: 3. Semantics, structure, and APIs of HTML documents

これはブラウザのimplicit submittionという仕様が関連している。

HTML仕様を読むと以下のようなことが書いてある。

  • formタグ内のテキストフィールドでEnterを押すと、自動で送信されるようにすべき(Implicit submission)
  • Enterを押すと、submitボタンにclick イベントが発生する
  • 入力フィールドのvalidationに引っかかったらformタグからinvalidイベントが発生する
  • もしvalidationに問題なかったら formタグからsubmitイベントが発生する
  • 誰もsubmitイベントをキャッチしなかったらformが送信される
  • formのaction属性が空だったら、ドキュメントが配置されているアドレスに送信する

解決方法

Enter押下時に自画面への遷移を防いで、なおかつ、ボタン押下時と同じふるまいにする。 そのために、Vuejsの機能を利用してsubmitイベントを黙殺して、自身が作成したハンドラを実行する。
参考 Vuejs イベント修飾子

<template>
  <form @submit.prevent="exec">
    <input type="text" placeholder="username" />
    <input type="text" placeholder="password" />
    <button type="submit">submit</button>
  </form>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    exec: function () {
      // 本来はajax通信をする
      console.log('exec')
    }
  }
}
</script>

f:id:kimulla:20191201140627g:plain

なぜsubmitにするか?

submitにするとHTML上でのバリデーションがかけられます。

<template>
  <form>
    <input type="email" placeholder="email" />
    <input type="text" placeholder="password" />
    <button type="button" @click="exec">submit</button>
  </form>
</template>

email形式のチェックが実行されない。 f:id:kimulla:20191201140738g:plain

<template>
  <form @submit.prevent="exec">
    <input type="email" placeholder="email" />
    <input type="text" placeholder="password" />
    <button type="submit">submit</button>
  </form>
</template>

email形式のチェックが実行される。

f:id:kimulla:20191201140700g:plain