Riotでのフォームの扱い方を紹介します。
DOM要素に直接アクセス
おそらく一番簡単でわかりやすい方法です。フォームがちょっとでも複雑になるとコードがカオスになりがちなので実務ではあまり使いません。
サッと簡単なフォームを作る時にはこれで十分ですね。
<app-form>
<form onsubmit="{ handleSubmit }">
<input type="email" name="email" placeholder="メールアドレス" />
<input type="password" name="password" placeholder="パスワード" />
<input type="checkbox" id="password_visible" onchange="{ handleCheckChange }">
<label for="password_visible">パスワード表示</l1abel>
<button>送信</button>
</form>
<script>
export default {
handleCheckChange(e) {
this.$('[name=password]').type = e.target.checked ? 'text' : 'password'
},
handleSubmit(e) {
e.preventDefault()
const email = this.$('[name=email]').value
const password = this.$('[name=password]').value
console.log({ email, password })
}
}
</script>
</app-form>
##form要素から値を取得
送信するだけのフォームならおすすめです。
DOMを検索しない分上の方法よりパフォーマンスはいいのですが、誤差ですね😅
<app-form>
<form onsubmit="{ handleSubmit }">
<input type="email" name="email" placeholder="メールアドレス" />
<input type="password" name="password" placeholder="パスワード" />
<button>送信</button>
</form>
<script>
export default {
handleSubmit(e) {
e.preventDefault()
const fields = e.target.elements
const email = fields['email'].value
const password = fields['password'].value
console.log({ email, password })
}
}
</script>
</app-form>
##stateにフォームの値を持つ
冗長だけど凝ったことをするならこれ一択ですね。
自分はフォームを作るとき大体あとから複雑になってくるので、最初から全部この方法で統一しています。
<app-form>
<form onsubmit="{ handleSubmit }">
<input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" />
<input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" />
<input type="checkbox" id="password_visible" onchange="{ handleCheckChange }">
<label for="password_visible">パスワード表示</l1abel>
<button>送信</button>
</form>
<script>
export default {
state: {
email: '',
password: '',
passwordType: 'password'
},
handleEmail(e) {
this.state.email = e.target.value
this.update()
},
handlePassword(e) {
this.state.password = e.target.value
this.update()
},
handleCheckChange(e) {
this.state.passwordType = e.target.checked ? 'text' : 'password'
this.update()
},
handleSubmit(e) {
e.preventDefault()
console.log(this.state)
}
}
</script>
</app-form>
さすがにフィールドごとにイベントハンドラーhandle...
を用意するのは冗長すぎるので、普段は一つのハンドラーで工夫しています。
- <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" />
- <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" />
+ <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleChange }" value="{ state.email }" />
+ <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handleChange }" value="{ state.password }" />
...
- handleEmail(e) {
- this.state.email = e.target.value
- this.update()
- },
- handlePassword(e) {
- this.state.password = e.target.value
- this.update()
- },
+ handleChange(e) {
+ this.state[e.target.name] = e.target.value
+ this.update()
+ },
##その他
name属性がないフィールドも扱う
<awesome-color-picker value="" on-change="" />
という感じのname属性のないカスタムなコンポーネントがある時 + なるべくhandleChange
一つにまとめたい
<app-form>
<form onsubmit="{ handleSubmit }">
<awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" />
<input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" />
</form>
<script>
export default {
state: {
text: '',
color: '#ffffff'
},
handleChange(name, value) {
this.state[name] = value
this.update()
},
handleSubmit(e) {
e.preventDefault()
console.log(this.state)
}
}
</script>
</app-form>
{ e => handleChange('text', e.target.value) }
← 好みの問題ですがこれが「なんか気持ち悪い...」なら
- <awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" />
- <input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" />
+ <awesome-color-picker on-change="{ handleChange('color') }" value="{ state.color }" />
+ <input type="text" oninput="{ handleChange('text') }" value="{ state.text }" />
...
- handleChange(name, value) {
- this.state[name] = value
- this.update()
- },
+ handleChange(name) {
+ return e => {
+ this.state[name] = e.target ? e.target.value : e;
+ this.update();
+ }
+ },
こっちの方がすっきりする気がします。
フォームが複雑になってくるとイベントハンドラ一つでカバーできないときもあるので、無理に一つにまとめずに複数のイベントハンドラを使いましょう。自分は単純なものは上にあったようなhandleChange
を使い、それ以外のものは個別にイベントハンドラを作ります。
##最後に
質問などがあれば気軽にコメントしてください!(^^♪