h:selectOneRadioのラジをボタンでいろいろやってみる

- 環境
    - CentOS Linux release 7.8.2003 (Core)
    - Payara Server 5.194
    - Eclipse IDE for Enterprise Java Developers.Version: 2020-03 (4.15.0)
    - JSF 2.3.9

# 選択肢を設定してみる
- 参考
    - [Jsf-selectoneradio-tag - Dev Guides](https://www.finddevguides.com/Jsf-selectoneradio-tag)
    - [selectOneRadio(JSF 2.1 View Declaration Language: Facelets Variant)](https://docs.oracle.com/javaee/6/javaserverfaces/2.1/docs/vdldocs/facelets/h/selectOneRadio.html)

|-|選択肢を指定するタグ|説明|
|:-:|:-:|:--|
|1つ1つ書く方法|f:selectItem|選択肢を1つ1つ指定する。<br>固定値で直書きしたい場合に便利。|
|SelectItemのリストを使う方法|f:selectItem|選択肢を格納する便利クラス[SelectItem](https://docs.oracle.com/javaee/7/api/javax/faces/model/SelectItem.html)に選択肢を設定して使う方法。<br>Enumなどの値を入れて選択肢にするのに便利。|
|オブジェクトのリストを使う方法|f:selectItem<b>s</b>|作ったクラスのプロパティを使って選択肢を作る方法。<br>データベースから取得したデータを選択肢にする場合に便利。|

どの方法でも同じ見た目のラジオボタンが作れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159761/56e59937-9a38-f060-ddbb-6487f1da6238.png)


## 1つ1つ書く方法

```xml:xhtml
<h5>1つ1つ書く方法</h5>
<h:selectOneRadio value="#{sampleBean.selected}">
  <f:selectItem itemValue="0" itemLabel="くま" />
  <f:selectItem itemValue="1" itemLabel="いぬ" />
  <f:selectItem itemValue="2" itemLabel="ねこ" />
</h:selectOneRadio>
```

## SelectItemのリストを使う方法

```xml:xhtml
<h5>SelectItemのリストを使う方法</h5>
<h:selectOneRadio value="#{sampleBean.selected}">
  <f:selectItems value="#{sampleBean.items}" />
</h:selectOneRadio>
```

## オブジェクトのリストを使う方法

```xml:xhtml
<h5>オブジェクトのリストを使う方法</h5>
<h:selectOneRadio value="#{sampleBean.selected}">
  <f:selectItems value="#{sampleBean.animals}" var="b" itemValue="#{b.no}" itemLabel="#{b.name}" />
</h:selectOneRadio>
```

## XHTML以外のコード
```java:SampleBean.java
package beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.model.SelectItem;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import codes.AnimalCode;
import lombok.Getter;
import lombok.Setter;

@Named
@ViewScoped
public class SampleBean implements Serializable {
    /** serialVersionUID. */
    private static final long serialVersionUID = -6782548672735889274L;
    /** SelectItemのリスト. */
    @Getter
    private List<SelectItem> items;
    /** 動物リスト. */
    @Getter
    private List<Animal> animals;
    /** 選択した値. */
    @Getter
    @Setter
    private Integer selected;

    /** Beanの初期化処理. */
    @PostConstruct
    public void init() {
        setAnimals();
        setItems();
    }

    /** SelectItemのリストを設定する. */
    private void setItems() {
        this.items = new ArrayList<SelectItem>();
        this.items.add(new SelectItem(AnimalCode.BEAR.getNo(), AnimalCode.BEAR.getName()));
        this.items.add(new SelectItem(AnimalCode.DOG.getNo(), AnimalCode.DOG.getName()));
        this.items.add(new SelectItem(AnimalCode.CAT.getNo(), AnimalCode.CAT.getName()));
    }

    /** 動物リストを設定する. */
    private void setAnimals() {
        var kuma = new Animal();
        kuma.setNo(0);
        kuma.setName("くま");
        kuma.setPlace("森");
        var dog = new Animal();
        dog.setNo(1);
        dog.setName("いぬ");
        dog.setPlace("犬小屋");
        var cat = new Animal();
        cat.setNo(2);
        cat.setName("ねこ");
        cat.setPlace("家");
        this.animals = new ArrayList<Animal>();
        this.animals.add(kuma);
        this.animals.add(dog);
        this.animals.add(cat);
    }
}
```

```java:Animal.java
package beans;

import java.io.Serializable;

import javax.faces.view.ViewScoped;
import javax.inject.Named;

import lombok.Data;

/** 動物クラス. */
@Data
@Named
@ViewScoped
public class Animal implements Serializable {
    /** serialVersionUID. */
    private static final long serialVersionUID = -6704219874078081663L;
    /** 番号. */
    Integer no;
    /** 名前. */
    String name;
    /** 場所. */
    String place;
}
```

```java:AnimalCode.java
package codes;

import lombok.Getter;
import lombok.Setter;

/** 動物コード列挙体. */
public enum AnimalCode {
    BEAR(0, "くま"),
    DOG(1, "いぬ"),
    CAT(2, "ねこ");

    /** 番号. */
    @Getter
    @Setter
    private int no;
    /** 名前. */
    @Getter
    @Setter
    private String name;

    /**
     * コンストラクタ.
     * @param no   番号.
     * @param name 名前.
     */
    private AnimalCode(int no, String name) {
        this.no = no;
        this.name = name;
    }
}
```

# 配置する
選択肢の並びは`layout`属性を使う。無駄にCSSで頑張って失敗した。

|layout|並び|
|:-:|:-:|
|lineDirection|横並び(デフォルト)|
|pageDirection|縦並び|
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159761/c7389072-95cc-759e-ee8f-38c98ebf4736.png)

## 縦並び配置
```xml:xhtml
<h5>縦並び配置</h5>
<h:selectOneRadio value="#{sampleBean.selected}" layout="pageDirection">
  <f:selectItems value="#{sampleBean.items}" />
</h:selectOneRadio>
```

## 他の要素と合わせて1行で表示

- ラジオボタンと他の要素(チェックボックスとか)を一緒に横並びにする方法
    1. ラジオボタンと他の要素を`h:panelGroup`で囲う
    2. 囲ったものにCSSでFlexbox(`display: flex;`)を設定する
    3. Flexbox内の子要素の配置方向がデフォルトで左からの横並びになる(`flex-direction: row;`)
    4. チェックボックスの`layout`は指定しない(デフォルトで横並びになる)
- 参考 : [【CSS】Flexboxの各プロパティの挙動を確認してみる | KuzLog](https://kuzlog.com/2017/01/18/495/#flex-direction)

```xml:さんぷる
<h5>他の要素と合わせて1行で表示</h5>
<h:panelGroup style="display: flex;">
  <h:selectBooleanCheckbox id="check" />
  <h:outputLabel for="check" value="チェックボックス"/>
  (
  <h:selectOneRadio value="#{sampleBean.selected}">
    <f:selectItems value="#{sampleBean.items}" />
  </h:selectOneRadio>
  )
</h:panelGroup>
```