根据JSF spec issue 329,我终于为 JSF 2.3 实现了它。使用新的group 属性,您现在可以在转发器组件中对单选按钮进行分组。
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectOneRadio group="foo" value="#{bean.selectedItem}">
<f:selectItem itemValue="#{item}" />
</h:selectOneRadio>
</h:column>
</h:dataTable>
它将根据 Mojarra 2.3.0-m07 提供。
在 JSF 2.3 之前,这对于标准 JSF <h:selectOneRadio> 来说并非易事。基本上,每一行中的单选按钮需要使用相同的输入 name 相互分组,以便在您选择一个单选按钮时取消选中其他单选按钮。但是它们没有被分组,它们都有自己的name,所以其他单选按钮永远不会被取消选中。
像 PrimeFaces 这样的组件库通过提供一个特殊的属性或列组件解决了这个问题。另请参阅this showcase example,它使用<p:column selectionMode="single"> 生成单个选择列。所选值由<p:dataTable> 的selection 属性引用。如果您已经在使用组件库并且它已经为您提供了这样的组件,那么您应该使用它。
在标准 JSF <h:dataTable> 和 <h:selectOneRadio> 中,您需要引入如下 JavaScript 解决方法,取消选中同一列中的所有其他单选按钮:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectOneRadio valueChangeListener="#{bean.setSelectedItem}"
onclick="dataTableSelectOneRadio(this);">
<f:selectItem itemValue="null" />
</h:selectOneRadio>
</h:column>
...
</h:dataTable>
与
public void setSelectedItem(ValueChangeEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
selectedItem = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
}
和
function dataTableSelectOneRadio(radio) {
var radioId = radio.name.substring(radio.name.lastIndexOf(':'));
for (var i = 0; i < radio.form.elements.length; i++) {
var element = radio.form.elements[i];
if (element.name.substring(element.name.lastIndexOf(':')) == radioId) {
element.checked = false;
}
}
radio.checked = true;
}