Vue.jsはサードパーティの便利なコンポーネントライブラリがたくさん出ていて、弊社ではElementというライブラリを使っています。
今回はElementでユーザー入力を受け付けるformを作るときに使うコンポーネント、el-formについて、素のHTMLのformと同じようにEnterを押したときにsubmitする(リクエストを送信する)実装に手間取ったので、紹介します。
何が問題なの?
当初、普通にsubmitイベントのハンドラを設定すればいいのでは?と思い以下のように設定してみました。
<template> <el-form :model="form" ref="form" @submit="login"> <el-form-item label="Eメール" prop="email"> <el-input type="email" v-model="form.email"></el-input> </el-form-item> <el-form-item label="パスワード" prop="password"> <el-input type="password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="default">ログイン</el-button> </el-form-item> </el-form> </template> <scrip> export default { name: 'LoginForm', data () { return { form: { email: '', password: '' } } }, methods: { login () { this.$axios.post('users/login', this.form) .catch(err => { const lastField = _.last(this.$refs.form.fields) lastField.validateMessage = 'Eメールまたはパスワードが間違っています' lastField.validateState = 'error' }) } } } </scrip>
これだと、loginメソッドが呼ばれませんでした。
解決
<template> <el-form :model="form" ref="form" @submit.native.prevent="login"> <el-form-item label="Eメール" prop="email"> <el-input type="email" v-model="form.email"></el-input> </el-form-item> <el-form-item label="パスワード" prop="password"> <el-input type="password" v-model="form.password"></el-input> </el-form-item> <el-form-item> <el-button type="default" native-type="submit">ログイン</el-button> </el-form-item> </el-form> </template> <scrip> export default { name: 'LoginForm', data () { return { form: { email: '', password: '' } } }, methods: { login () { this.$axios.post('users/login', this.form) .catch(err => { const lastField = _.last(this.$refs.form.fields) lastField.validateMessage = 'Eメールまたはパスワードが間違っています' lastField.validateState = 'error' }) } } } </scrip>
直したのは3ヶ所です。
- @submit -> @submit.native
.native
修飾子について公式ドキュメントが見つからないのですが、これはVueコンポーネントではなくDOMのイベントに対するハンドラを設定したいときに使います。el-formコンポーネントはsubmitイベントを発火しないので、これで通常のformエレメントのsubmitイベントをキャッチします。 - @submit.native -> @submit.native.prevent
本当にフォームを送信されるのは意図しないので.prevent
修飾子をつけてsubmitイベントを阻止します。 <el-button native-type="submit">
native-type
プロパティを渡して、buttonエレメントにtypeアトリビュートをつけます。これをつけないとフォーム内でenterを押してもsubmitイベントが発火しませんでした。
keypressイベントはダメ?
上記3つに気づくまでにいろいろ試行錯誤する中で、<el-form @keypress.enter.native="login">
でいけるのでは?と思い試してみました。
結果、今回の例のログインフォームのような半角英数字しか入力されないフォームならそれで問題ないと思います。
が、日本語の入力要素がある場合、変換→確定のenterを拾ってしまい、ユーザーが意図しないタイミングでリクエストが送信されてしまうという問題が発生しました。
素直にsubmitイベントを拾いましょう。
まとめ
Vue.jsはコンポーネントやディレクティブの形でライブラリを取り入れられるのでわかりやすいですね。
今回は省きましたがフォームのバリデーション・エラー表示もelementはプロパティを渡すだけで簡単にやってくれます。便利!