You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JSF实现动态行列表格的多列垂直单选按钮?

动态行列表格中实现列内单选互斥的JSF方案

核心思路

HTML原生单选按钮的互斥依赖相同的name属性,因此我们可以通过JSF组件绑定同一列的单选按钮到同一个后台属性,让组件自动生成相同的name;或者利用PrimeFaces的自定义布局单选组件来适配动态渲染场景。


方案一:使用标准JSF组件(h:selectOneRadio)

通过ui:repeat动态生成行列,将同一列的单选按钮绑定到后台Map的同一key下,确保组件生成相同的name属性,实现列内互斥。

前台代码

<h:form>
  <table border="1">
    <!-- 表头 -->
    <thead>
      <tr>
        <ui:repeat value="#{dynamicTableBean.columns}" var="column">
          <th>#{column.label}</th>
        </ui:repeat>
      </tr>
    </thead>
    <!-- 表体 -->
    <tbody>
      <ui:repeat value="#{dynamicTableBean.rows}" var="row">
        <tr>
          <ui:repeat value="#{dynamicTableBean.columns}" var="column">
            <td>
              <!-- 每个单元格仅一个单选选项,绑定到对应列的选中值 -->
              <h:selectOneRadio value="#{dynamicTableBean.columnSelectedValues[column.id]}" layout="pageDirection">
                <f:selectItem itemValue="#{row.id}" itemLabel="" />
              </h:selectOneRadio>
            </td>
          </ui:repeat>
        </tr>
      </ui:repeat>
    </tbody>
  </table>
  <h:commandButton value="提交选中数据" action="#{dynamicTableBean.handleSubmit}" />
</h:form>

后台Bean代码

@ManagedBean
@ViewScoped
public class DynamicTableBean implements Serializable {
    // 动态列数据(含唯一标识id和显示标签label)
    private List<TableColumn> columns;
    // 动态行数据(含唯一标识id)
    private List<TableRow> rows;
    // 存储每列的选中行ID:key为列id,value为选中的行id
    private Map<String, String> columnSelectedValues = new HashMap<>();

    @PostConstruct
    public void initData() {
        // 模拟初始化动态列和行,实际可从数据库/接口获取
        columns = Arrays.asList(
            new TableColumn("col_01", "项目A"),
            new TableColumn("col_02", "项目B"),
            new TableColumn("col_03", "项目C")
        );
        rows = Arrays.asList(
            new TableRow("row_01"),
            new TableRow("row_02"),
            new TableRow("row_03")
        );
    }

    public void handleSubmit() {
        // 处理提交的选中数据
        for (Map.Entry<String, String> entry : columnSelectedValues.entrySet()) {
            System.out.printf("列[%s] 选中行ID:%s%n", entry.getKey(), entry.getValue());
        }
    }

    // Getter & Setter
    public List<TableColumn> getColumns() { return columns; }
    public List<TableRow> getRows() { return rows; }
    public Map<String, String> getColumnSelectedValues() { return columnSelectedValues; }
    public void setColumnSelectedValues(Map<String, String> columnSelectedValues) { this.columnSelectedValues = columnSelectedValues; }
}

// 列数据辅助类
class TableColumn implements Serializable {
    private String id;
    private String label;

    public TableColumn(String id, String label) {
        this.id = id;
        this.label = label;
    }

    // Getter & Setter
    public String getId() { return id; }
    public String getLabel() { return label; }
}

// 行数据辅助类
class TableRow implements Serializable {
    private String id;

    public TableRow(String id) {
        this.id = id;
    }

    // Getter & Setter
    public String getId() { return id; }
}

方案二:使用PrimeFaces组件解决兼容问题

如果使用PrimeFaces,p:selectOneRadio与ui:repeat的兼容问题可通过**自定义布局(layout="custom")**解决,配合p:radioButton手动渲染单选选项。

前台代码

<h:form>
  <table border="1">
    <thead>
      <tr>
        <ui:repeat value="#{dynamicTableBean.columns}" var="column">
          <th>#{column.label}</th>
        </ui:repeat>
      </tr>
    </thead>
    <tbody>
      <ui:repeat value="#{dynamicTableBean.rows}" var="row">
        <tr>
          <ui:repeat value="#{dynamicTableBean.columns}" var="column">
            <td>
              <p:selectOneRadio value="#{dynamicTableBean.columnSelectedValues[column.id]}" layout="custom">
                <f:selectItem itemValue="#{row.id}" />
              </p:selectOneRadio>
              <!-- 关联父级selectOneRadio,渲染单选按钮 -->
              <p:radioButton for="@parent" itemValue="#{row.id}" />
            </td>
          </ui:repeat>
        </tr>
      </ui:repeat>
    </tbody>
  </table>
  <p:commandButton value="提交" action="#{dynamicTableBean.handleSubmit}" ajax="false" />
</h:form>

说明

  • layout="custom"让p:selectOneRadio不自动渲染选项,由p:radioButton手动控制
  • for="@parent"将单选按钮关联到父级的p:selectOneRadio,确保同一列的组件共享同一个name属性,实现互斥

注意事项

  1. 后台Map需提前初始化(如HashMap),避免空指针异常
  2. 使用@ViewScoped作用域,确保提交时数据不丢失
  3. 若行/列数据来自外部数据源,需保证每个行、列的id唯一,避免单选组冲突

内容的提问来源于stack exchange,提问作者DaniEll

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:24:10