カジュアルな技術ノート

小難しい技術のお話をできるだけわかりやすく...

th:field と th:object によるフォームバインディング機能(inputタグ・radio編)

th:fieldth:object が提供する機能説明の続きです。
今回は inputタグの type="radio" をみていきましょう。

th:fieldth:object の提供機能はタグや属性値によって異なります。
サポートされているタグの一覧はこちら

casual-tech-note.hatenablog.com

inputタグ・type="radio" における提供機能

input タグの type="radio" における th:fieldth:object の提供機能を示していきたいと思います。実は inputタグ・type="radio" のカテゴリー型における提供機能と、とても似ています。
→ 参考: inputタグ・type="checkbox" における提供機能

f:id:shin-kinoshita:20181027180045p:plain

  1. id 属性th:field に指定した変数名を 連番付き で代入
    → 詳細は 「連番付きの id 属性」を参考

  2. name 属性th:field に指定した変数名を代入

  3. checked 属性 の設定
    value に指定された値とフィールドに指定した値が同じであるなら checked 属性 が付与される。
    → 詳細は 「checked 属性の設定」を参考

  4. value 属性 の設定
    別途 value 属性で指定することが必須となる。
    → 詳細は 「カテゴリー型における value 属性値の設定」を参考

サンプルコード

毎回のことながら、簡単なサンプル画面とコードをみていきましょう!
f:id:shin-kinoshita:20181021165714p:plain

名前と性別を尋ねます。
性別によって色と敬称を変えてみました!というページになります。
Input Page と Output Page の実際のコードは次の通りです。

<!-- Input Page -->
<h1>Input Page</h1>
<form action="/binding/input/radio" method="post" th:object="${radioForm}">
  <p>name</p>
  <input type="text" th:field="*{name}"/>
  <p>gender</p>
  <input type="radio" th:field="*{gender}" value="male"/>
  <label th:for="${#ids.prev('gender')}" th:text="male"></label>
  <input type="radio" th:field="*{gender}" value="female"/>
  <label th:for="${#ids.prev('gender')}" th:text="female"></label>
  <br/>
  <input type="submit" value="submit"/>
</form>
<!-- Output Page -->
<h1>Output Page</h1>
<p>Welcome for visiting this page,
  <span th:text="${radioForm.gender == 'male' ? 'Mr.' : 'Ms.'} + ${radioForm.name}"
        th:style="${radioForm.gender == 'male' ? 'color: blue;' : 'color: red;'} + 'font-size: 20px'"></span>
</p>

結果 Input Page のレンダリング結果は次のようになります。
f:id:shin-kinoshita:20181021163511p:plain

デフォルトで checked 属性が male のラジオボタンに付与されていますね。
これは、フォームオブジェクトの gender フィールドに "male" を初期値として与えることで付与されます。

public class RadioForm {
    private String name;
    // これで male のラジオボタンはチェックされた状態でレンダリング
    private String gender = "male";  

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getGender() {
        return gender;
    }
}

今回も念のため、完全版フロントエンドバックエンドコード。

カテゴリー型チェックボックスとの違い

今回紹介している inputタグ・type="radio" における提供機能は本当にカテゴリー型のチェックボックスと似ています。なのでここでは異なる点を取り上げてみます。
ぜひカテゴリー型のチェックボックスと比較してみてください!

対応するフィールドの型

すでに少しバックエンドのコードも見ましたが、性別を受け取るためのフィールド gender は String 型を採用しています。カテゴリ型チェックボックスであれば、ここは List などの Collection を採用していました。

// ラジオボタンでのフィールド例
private String gender = "male"; 
// チェックボックスでのフィールド例
private List<String> favoriteFruits = Collections.singletonList("apple");

なぜ型が異なるかという理由は単純で、ラジオボタンは必ず一つの値しか格納しないためです。

今回の例では、性別は男と女しかなく、必ず片方が選択されることを想定しています。

デフォルト値の設定

「対応するフィールドの型」での話とも関連しますが、ラジオボタンでは必ず一つの値が格納されていることを想定しています。複数の値を格納することもないですが、同時に空の状態も想定していません。

そのため 必ずデフォルト値を格納しておくことが望ましいです。

初期値を特に設定していなければ gender の値には null が格納されます。 つまり gender の値が "male" でも "female" でもないため、どちらのラジオボタンもチェックされていない状態でレンダリングされることになります。バリデーションの実装をしていない状態ではこのまま選択せずに送信することも可能です。そのままではヌルポなど、危険な状態になりえるかもしれません。

また、カテゴリー型チェックボックスでは提供されていた type="hidden" の input タグもラジオボタンでは提供されていません。
参考: type="hidden" の input タグ

この input タグは特定のフィールドの値が送信されないことを想定して付与されるというものでした。このタグが付与されないということは、必ずフィールドの値が送信されることを想定しているからだと思われます。

まとめ

チェックボックスラジオボタンは、実用面でも似ていますが、使い分けはしっかり存在します。
複数項目を選択するとか、しないとか。。

実装も似ているんだけど、微妙に違っていて、それはちょうど使い分けの違いと対応するようになっていると、この記事を書いてて思いました。

ラジオボタンにおける提供機能の紹介でしたが、ラジオボタンチェックボックスの違いがより明確になればなお嬉しいです。