こちらの件です。
雑にかいた
— こにふぁー (@konifar) 2018年1月29日
すでに議論され尽くされてる感はあるので他の人の考えも聞いてみたいです
フォームバリデーションと送信ボタンの状態の最適解 - Konifar's ZATSU https://t.co/YvPhkM05gg
自分がよく関わっている業務アプリの世界では、UIパーツの非活性(disabled)はあまり好まれません(度々 Reject されます)。その一番の理由は、「なぜボタンが押せないのかが分からない」ことです(利用ユーザーがIT機器に疎い人が多いのでそれだけでパニクることも)。ならばその理由を画面上のどこかに表示してやろうと策を練るよりも、単純に「エラーがあったら DialogBox でその理由と対処方法を表示させたろう」という方法が、実装コストが最も低く、業務アプリ利用者にもわかりやすい、というのが経験・感覚的にあります。
しかしそれではあまりにもモダンでないとも感じるので、個人的には、次点として採用したいのは↓の手法です。
最初の1回は間違いがあってもとりあえず送信ボタンを押させてあげて、その後はリアルタイムチェックを有効にする派 / “フォームバリデーションと送信ボタンの状態の最適解 - Konifar's ZATSU” https://t.co/yWaszGdAkH
— なかざん@ジャバスクリプトニュービー (@Nkzn) 2018年1月30日
実際にそれを実装してみました、 RxProperty を使って。 最近ちょうどフォームバリデーションのサンプルを実装した例↓
があるので、これをカスタマイズしてみます。
こんな感じのものを作ります。
RxProperty は、ViewModel が公開するプロパティとして利用するものですが、それに Validator を持たせることができます。
val nickname = RxProperty<String>("")
.setValidator {
if (it.length < 2) "ニックネームは2文字以上にしてください" else null }
のようにプロパティの定義と共に設定すれば、画面表示直後からValidatorは作動しますが、ボタンが押されるまではバリデーションしないのであれば、設定のタイミングを遅らせるだけです。
val nickname = RxProperty<String>("")
val nickNameValidator : (String)->String? = {
if (it.length < 2) "ニックネームは2文字以上にしてください" else null }
private var isFirstExecute = true
/** 登録ボタンを押したとき */
val register = canRegistration.toRxCommand<NoParameter>().apply { this.subscribe {
// 最初にボタンが押されたときに、Validator を設定する(フラグを使っているのがなんかダサい)
if (isFirstExecute) {
isFirstExecute = false
nickname.setValidator(nickNameValidator, true)
if (!this.canExecute()) { return@subscribe }
}
_toast.postValue("RegistrationCompleteActivity へ移動するよ")
}
ちなみに
val nickname = RxProperty<String>("")
.setValidator ({
if (it.length < 2) "ニックネームは2文字以上にしてください" else null },
false)
とする(setValidator
の第2引数を false
にする)と、画面表示直後の初回のバリデーションを行わない、すなわち、「最初から登録ボタンは押せるが、リアルタイムにバリデーションも行う」ようにもできます。
RxProperty に限らないんですけど、プロパティ/バリデータ/活性非活性判定・変更処理が適切に分離されていれば、それらの組み合わせを変えるだけなのでいかようにでもできますね。急な仕様変更にも割と容易に対応できるということで。