如何使 h:dataTable 中选择的 h:selectOneRadio 在回发时保持选中状态?
How to make selected h:selectOneRadio of h:dataTable remain selected on postback?
正常情况下是这样的:
<h:form>
<h:selectOneRadio value="#{bean.gender}">
<f:selectItem itemValue="Male" itemLabel="Male" />
<f:selectItem itemValue="Female" itemLabel="Female" />
<f:selectItem itemValue="Other" itemLabel="Other" />
</h:selectOneRadio>
<h:commandButton value="Submit" action="#{bean.action}" />
</h:form>
Select 点击一个单选按钮会取消选择另一个单选按钮,并且单选按钮将在回发时保持选中状态。 (呈现相同视图时)
但是,当我们处理像 <h:dataTable>
这样的迭代组件时,选择会丢失。
考虑片段:
<h:form id="hashMapFormId">
<b>HASH MAP:</b>
<h:dataTable value="#{playersBean.dataHashMap.entrySet()}" var="t" border="1">
<h:column>
<f:facet name="header">Select</f:facet>
<h:selectOneRadio id="radiosId" onclick="deselectRadios(this.id);"
value="#{playersBean.select}">
<f:selectItem itemValue="null"/>
</h:selectOneRadio>
</h:column>
</h:dataTable>
<h:commandButton value="Show Hash Map Selection"
action="#{playersBean.showSelectedPlayer()}" />
</h:form>
通过简单的 JavaScript-
选择一个单选按钮时取消选择其他单选按钮
function deselectRadios(id) {
var f = document.getElementById("hashMapFormId");
for (var i = 0; i < f.length; i++)
{
var e = f.elements[i];
var eid = e.id;
if (eid.indexOf("radiosId") !== -1) {
if (eid.indexOf(id) === -1) {
e.checked = false;
} else {
e.checked = true;
}
}
}
}
触发 GET 请求:
Select单选按钮:
现在按下提交按钮,响应:
您看到单选按钮在回发时被取消选中。如何解决这个缺点?
我很清楚这是因为这个组件属性 itemValue
是 null
:
<f:selectItem itemValue="null"/>
这个技巧是 JSF 1.x / 2.0/2.1 的遗留物,当时无法在 <h:dataTable>
中使用 <h:selectOneRadio>
进行单行选择。这个技巧起源于我 10 年前的博客文章 Using Datatables - Select row by radio button。
根本问题是,HTML 单选按钮是根据它们的 name
属性分组的,因此网络浏览器知道在选择一个按钮时要取消选择哪些按钮。但是 JSF 通过设计为每个 <h:dataTable>
项目生成一个不同的项目,行索引是内联的,因此它们不能被分组,因此基于 JavaScript 的解决方法。
从 JSF 2.2 开始,有了新的 passthrough elements and attributes feature, it's however possible to force the name
attribute to the value of your choice and capture the selected item via a helper <h:inputHidden>
. This is fleshed out in another blog article of me, from previous year: Custom layout with h:selectOneRadio in JSF 2.2。文章以<ui:repeat>
为例,可以改写为<h:dataTable>
如下。
<h:form>
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<input type="radio" jsf:id="item" a:name="#{hiddenItem.clientId}"
value="#{item.id}" a:checked="#{item.id eq bean.selectedItemId ? 'checked' : null}" />
</h:column>
<h:column>#{item.id}</h:column>
<h:column>#{item.name}</h:column>
</h:dataTable>
<h:inputHidden id="selectedItem" binding="#{hiddenItem}" value="#{bean.selectedItemId}"
rendered="#{facesContext.currentPhaseId.ordinal ne 6}" />
<h:commandButton id="submit" value="Submit" action="#{bean.submit}" />
</h:form>
@Named
@ViewScoped
public class Bean implements Serializable {
private List<Item> items;
private Long selectedItemId;
// ...
public void submit() {
System.out.println("Selected item ID: " + selectedItemId);
}
// ...
}
是的,选中的单选按钮在回发时仍然处于选中状态。您还可以传递整个实体,这只需要 <h:inputHidden>
.
上的转换器
正常情况下是这样的:
<h:form>
<h:selectOneRadio value="#{bean.gender}">
<f:selectItem itemValue="Male" itemLabel="Male" />
<f:selectItem itemValue="Female" itemLabel="Female" />
<f:selectItem itemValue="Other" itemLabel="Other" />
</h:selectOneRadio>
<h:commandButton value="Submit" action="#{bean.action}" />
</h:form>
Select 点击一个单选按钮会取消选择另一个单选按钮,并且单选按钮将在回发时保持选中状态。 (呈现相同视图时)
但是,当我们处理像 <h:dataTable>
这样的迭代组件时,选择会丢失。
考虑片段:
<h:form id="hashMapFormId">
<b>HASH MAP:</b>
<h:dataTable value="#{playersBean.dataHashMap.entrySet()}" var="t" border="1">
<h:column>
<f:facet name="header">Select</f:facet>
<h:selectOneRadio id="radiosId" onclick="deselectRadios(this.id);"
value="#{playersBean.select}">
<f:selectItem itemValue="null"/>
</h:selectOneRadio>
</h:column>
</h:dataTable>
<h:commandButton value="Show Hash Map Selection"
action="#{playersBean.showSelectedPlayer()}" />
</h:form>
通过简单的 JavaScript-
选择一个单选按钮时取消选择其他单选按钮 function deselectRadios(id) {
var f = document.getElementById("hashMapFormId");
for (var i = 0; i < f.length; i++)
{
var e = f.elements[i];
var eid = e.id;
if (eid.indexOf("radiosId") !== -1) {
if (eid.indexOf(id) === -1) {
e.checked = false;
} else {
e.checked = true;
}
}
}
}
触发 GET 请求:
Select单选按钮:
现在按下提交按钮,响应:
您看到单选按钮在回发时被取消选中。如何解决这个缺点?
我很清楚这是因为这个组件属性 itemValue
是 null
:
<f:selectItem itemValue="null"/>
这个技巧是 JSF 1.x / 2.0/2.1 的遗留物,当时无法在 <h:dataTable>
中使用 <h:selectOneRadio>
进行单行选择。这个技巧起源于我 10 年前的博客文章 Using Datatables - Select row by radio button。
根本问题是,HTML 单选按钮是根据它们的 name
属性分组的,因此网络浏览器知道在选择一个按钮时要取消选择哪些按钮。但是 JSF 通过设计为每个 <h:dataTable>
项目生成一个不同的项目,行索引是内联的,因此它们不能被分组,因此基于 JavaScript 的解决方法。
从 JSF 2.2 开始,有了新的 passthrough elements and attributes feature, it's however possible to force the name
attribute to the value of your choice and capture the selected item via a helper <h:inputHidden>
. This is fleshed out in another blog article of me, from previous year: Custom layout with h:selectOneRadio in JSF 2.2。文章以<ui:repeat>
为例,可以改写为<h:dataTable>
如下。
<h:form>
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<input type="radio" jsf:id="item" a:name="#{hiddenItem.clientId}"
value="#{item.id}" a:checked="#{item.id eq bean.selectedItemId ? 'checked' : null}" />
</h:column>
<h:column>#{item.id}</h:column>
<h:column>#{item.name}</h:column>
</h:dataTable>
<h:inputHidden id="selectedItem" binding="#{hiddenItem}" value="#{bean.selectedItemId}"
rendered="#{facesContext.currentPhaseId.ordinal ne 6}" />
<h:commandButton id="submit" value="Submit" action="#{bean.submit}" />
</h:form>
@Named
@ViewScoped
public class Bean implements Serializable {
private List<Item> items;
private Long selectedItemId;
// ...
public void submit() {
System.out.println("Selected item ID: " + selectedItemId);
}
// ...
}
是的,选中的单选按钮在回发时仍然处于选中状态。您还可以传递整个实体,这只需要 <h:inputHidden>
.