JSF HTML5-Friendly Markup における selectManyCheckbox の扱い方


はじめに

JSF の <h:selectManyCheckbox> タグは使わずに、<h:selectBooleanCheckbox> タグで代替しましょう という話です。


selectManyCheckbox タグ

JSF の HTML BASIC タグである selectManyCheckbox のレンダリング結果は HTML のテーブルとして展開されます。


バッキングビーンで以下のようなプロパティがあったとします。

private List<Item> selectItems;
private List<Long> selectedIds;

selectItems が選択肢、selectedIds にチェックボックスの選択対象を受ける場合、テンプレートでは selectManyCheckbox タグを使って以下のようになります。

<h:selectManyCheckbox value="#{backing.selectedIds}">
    <f:selectItems value="#{backing.selectItems}" var="_var"
        itemLabel="#{_var.name}" itemValue="#{_var.id}" />
</h:selectManyCheckbox>


出力は以下のようになります。

f:id:Naotsugu:20210124204006p:plain


この場合のレンダリング結果は、以下のようにテープルを使った HTML となります。

<table>
  <tr>
    <td>
      <input name="form:j_idt29" id="form:j_idt29:0" value="1" type="checkbox" />
      <label for="form:j_idt29:0" class="">check item 1</label>
    </td>
    <td>
        <input name="form:j_idt29" id="form:j_idt29:1" value="2" type="checkbox" />
        <label for="form:j_idt29:1" class="">check item 2</label>
    </td>
  </tr>
</table>

チェックボックスは横方向に列挙するような固定レイアウトが強要されます。

テンプレートには現れないテーブルが勝手に生成されるため、スタイルの割当がやりにくく、とても使いにくいものになります。


selectBooleanCheckbox タグで代替する

標準レイアウトが望ましくない場合は、selectManyCheckbox ではなく、selectBooleanCheckbox タグを使い <ui:repeat> してあげるのが良いです。


バッキングビーン側は以下のように Map で受ける形にします。

private List<Item> selectItems;
private Map<Long, Boolean> selectedIds;

テンプレートは以下のような定義になります。

<ui:repeat value="#{backing.selectItems}" var="_var">
  <h:selectBooleanCheckbox id="ids" value="#{backing.selectedIds[_var.id]}" />
  <h:outputLabel for="ids" value="#{_var.name}" />
</ui:repeat>


しかし今どきであれば、HTML5-Friendly Markup を使うことになるでしょう。


HTML5-Friendly Markup

JSF 2.2 から導入された HTML5-Friendly Markup により、先のテンプレートは、スタイルも当てて以下のように書くことができます。

<ui:repeat value="#{backing.selectItems}" var="_var">
    <div class="form-check">
        <input class="form-check-input" type="checkbox"
                    jsf:id="ids" jsf:value="#{backing.selectedIds[_var.id]}"/>
        <label class="form-check-label" jsf:for="ids">#{_var.name}</label>
    </div>
</ui:repeat>

<input type="checkbox"> タグの中に jsf: で装飾した属性があれば、<h:selectBooleanCheckbox> として解釈されます。


出力結果は以下のようになります(ここでは Bootstrap のスタイルを当てています)。

f:id:Naotsugu:20210124203717p:plain

<div class="form-check">
    <input id="form:j_idt29:0:ids" name="form:j_idt29:0:ids" type="checkbox" class="form-check-input" />
    <label for="form:j_idt29:0:ids" class="form-check-label">check item 1</label>
</div>
<div class="form-check">
    <input id="form:j_idt29:1:ids" name="form:j_idt29:1:ids" type="checkbox" class="form-check-input" />
    <label for="form:j_idt29:1:ids" class="form-check-label">check item 2</label>
</div>