谷本 心 in せろ部屋

はてなダイアリーから引っ越してきました

複数フィールドバリデーションは、ラベルをバリデータが持った方が良い

最近、複数フィールドバリデーションを、実案件でモリモリ使っています。
具体的には、複数フィールドに分かれた「年」「月」「日」に対して

  • 全部入力されなかったらスルー
  • どれか入力したら、他が一つでも入力されていないエラー
  • 全部入力されたら、存在する日付かどうかを確認する

という感じです。


そんな事をやっていると、タイトルの件に気付きました。
例えば、こんなバリデーションです。

生年月日

<input type="text" id="year" m:label="年" m:value="#{xxxDto.year}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

<input type="text" id="month" m:label="月" m:value="#{xxxDto.month}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

<input type="text" id="day" m:label="日" m:value="#{xxxDto.day}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

こうやって、複数フィールドをグループ化して、バリデーションを行います。
内部実装はキモいので省略します(笑)
# 要望が高ければ、後日、S2JSFにもコントリビュートします。


さて、ここで、いずれかの項目が入力されておらず、バリデーションエラーが発生した時、
どのようなエラーメッセージを出せば良いでしょうか。
こんな案が考えられます。

  • 年、月、日 : すべて入力してください。
  • 生年月日 : すべて入力してください。

どちらでも構わないか、前者が若干好ましい、ぐらいでしょう。


同様に、日付が存在しなかった場合は、どうでしょうか。

  • 年、月、日 : 正しい日付を入力してください。
  • 生年月日 : 正しい日付を入力してください。

これは後者の方が好ましいでしょう。


しかし、各フィールドは「年」「月」「日」であって、生年月日ではありません。
では、こんな風にHTMLを記述すれば良いのでしょうか。

<input type="text" id="year" m:label="生年月日" m:value="#{xxxDto.year}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

<input type="text" id="month" m:label="生年月日" m:value="#{xxxDto.month}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

<input type="text" id="day" m:label="生年月日" m:value="#{xxxDto.day}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday"/>
</input>

今度は、それぞれの「年」「月」「日」が分からなくなりました。
しかも、xxxDto.yearがIntegerなどだと、NumberConverterが自動設定され、
数字以外が入力された場合には、以下のようなエラーメッセージが表示されます。

生年月日 : 形式が正しくありません。

これでは、どのフィールドの形式が間違っているか、分かりません。


そんな事を考えていると、結論はこうなりました。

<input type="text" id="year" m:label="年" m:value="#{xxxDto.year}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday" m:label="生年月日"/>
</input>

<input type="text" id="month" m:label="月" m:value="#{xxxDto.month}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday" m:label="生年月日"/>
</input>

<input type="text" id="day" m:label="日" m:value="#{xxxDto.day}">
  <span m:inject="s:validator" m:binding="#{multiFieldDateValidator}"
    m:groupId="birtyday" m:label="生年月日"/>
</input>

これなら、各フィールドの変換エラーにも、
全体のバリデーションエラーにも上手く対応できます。



でも、ホントはこう書きたいんですよね。

<input type="text" id="year" m:label="年" m:value="#{xxxDto.year}" />
<input type="text" id="month" m:label="月" m:value="#{xxxDto.month}" />
<input type="text" id="day" m:label="日" m:value="#{xxxDto.day}" />
<span m:inject="s:validator" m:binding="#{groupDateValidator}"
    m:targetId="year,month,day" m:label="生年月日" />

JSFでは無理な書き方ですが、随分とスッキリします。