[英]How to use <h:selectBooleanCheckbox> in <h:dataTable> or <ui:repeat> to select multiple items?
I have a Facelets page with a <h:dataTable>
.我有一个带有
<h:dataTable>
的 Facelets 页面。 In each row there is a <h:selectBooleanCheckbox>
.在每一行中都有一个
<h:selectBooleanCheckbox>
。 If the checkbox is selected the object behind the corresponding row should be set in the bean.如果选中复选框,则应在 bean 中设置相应行后面的对象。
<h:selectManyCheckbox>
?<h:selectManyCheckbox>
会更好吗?Your best bet is to bind the <h:selectBooleanCheckbox>
value with a Map<Item, Boolean>
property where Item
represents the object behind the corresponding row.最好的办法是将
<h:selectBooleanCheckbox>
值与Map<Item, Boolean>
属性绑定,其中Item
表示相应行后面的对象。
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectBooleanCheckbox value="#{bean.checked[item]}" />
</h:column>
...
</h:dataTable>
<h:commandButton value="submit" action="#{bean.submit}" />
public class Bean {
private Map<Item, Boolean> checked = new HashMap<Item, Boolean>();
private List<Item> items;
public void submit() {
List<Item> selectedItems = checked.entrySet().stream()
.filter(Entry::getValue)
.map(Entry::getKey)
.collect(Collectors.toList());
checked.clear(); // If necessary.
// Now do your thing with selectedItems.
}
// ...
}
You see, the map is automatically filled with all table items as key and the checkbox value is automatically set as map value associated with the item as key.您会看到,地图自动填充所有表项作为键,复选框值自动设置为与作为键的项目关联的地图值。
This only requires that the Item#equals()
and Item#hashCode()
is properly implemented as per their contracts.这只需要
Item#equals()
和Item#hashCode()
根据他们的合同正确实施。
If you can't guarantee that, then you'd better use a Map<RowId, Boolean>
instead where RowId
represents the type of the row identifier.如果不能保证,那么最好使用
Map<RowId, Boolean>
代替RowId
表示行标识符的类型。 Let's take an example that you've a Item
object whose identifier property id
is a Long
:让我们举个例子,你有一个
Item
对象,它的标识符属性id
是Long
:
public class Item {
private Long id;
// ...
}
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:selectBooleanCheckbox value="#{bean.checked[item.id]}" />
</h:column>
...
</h:dataTable>
<h:commandButton value="submit" action="#{bean.submit}" />
public class Bean {
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
private List<Item> items;
public void submit() {
List<Item> selectedItems = items.stream()
.filter(item -> checked.get(item.getId()))
.collect(Collectors.toList());
checked.clear(); // If necessary.
// Now do your thing with selectedItems.
}
// ...
}
In the following example I am using checkboxes to select two or more products to allow the user to compare product specifications on a new web page using JSF 2.0.在以下示例中,我使用复选框来选择两个或更多产品,以允许用户使用 JSF 2.0 在新网页上比较产品规格。
It took me a good while to find the following problem (totally obvious now of course) so thought it worth a mention for those trying to use pagination with BalusC's code above (nice answer BalusC, much simpler than I ever imagined it would be).我花了很长时间才找到以下问题(当然现在很明显),所以认为对于那些试图在上面的 BalusC 代码中使用分页的人来说值得一提(BalusC 的答案很好,比我想象的要简单得多)。
If you are using pagination you will get nullpointers at the line:如果您使用分页,您将在该行获得空指针:
if (checked.get(item.getId()))
if (checked.get(item.getId()))
-in BalusC's code above. -在上面的 BalusC 代码中。
This is because only displayed check boxes are added to the Map (doh; slap forehead).这是因为只有显示的复选框才会添加到地图中(doh;拍前额)。 For those products whose check boxes are never displayed, due to pagination, this line will result in a null pointer error and a check needs to be added to ignore these null pointers (assuming that all check boxes are unchecked on page load).
对于那些复选框从不显示的产品,由于分页,此行将导致空指针错误,需要添加一个检查以忽略这些空指针(假设在页面加载时所有复选框都未选中)。 In order for the user to tick a check box then they need to display the pagination page so all works well there after.
为了让用户勾选复选框,他们需要显示分页页面,以便之后一切正常。
If some or all of the check boxes are required to be ticked on first page load then this will be of no help to you...you will have to manually add those to the Map in order for them to be displayed correctly on page load.如果需要在第一页加载时勾选部分或全部复选框,那么这对您没有帮助...您必须手动将它们添加到地图中,以便它们在页面加载时正确显示.
Note: because I am using a JPA 'Entity class from database' object I also needed to use @Transient for the id in my ProductTbl Entity Class as all variables are considered columns in the database by JPA, by default, unless prefixed with @Transient.注意:因为我使用的是 JPA '来自数据库的实体类' 对象,所以我还需要在我的 ProductTbl 实体类中使用 @Transient 作为 ID,因为默认情况下,所有变量都被 JPA 视为数据库中的列,除非以 @Transient 为前缀. Also I am using a second link to reset the check boxes, which calls clearSelections(), and my 'submit' is a link calling compareSelectedProducts() rather than a Submit button.
此外,我正在使用第二个链接来重置复选框,它调用 clearSelections(),我的“提交”是一个调用 compareSelectedProducts() 的链接,而不是一个提交按钮。
The full code is as follows:完整代码如下:
In the 'ProductTbl' Entity class derived from the database :在从数据库派生的“ProductTbl”实体类中:
@Transient
private Long id;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
In the backing bean 'ProductSelection':在支持 bean 'ProductSelection' 中:
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
private String errorMessage = "";
// List of all products.
private List<ProductTbl> products;
// List of products to compare.
private List<ProductTbl> compareProducts;
// Setters and getters for above...
public String compareSelectedProducts()
{
// Reset selected products store.
compareProducts = new ArrayList();
for (ProductTbl item: products)
{
// If there is a checkbox mapping for the current product then...
if(checked.get(item.getId()) != null)
{
// If checkbox is ticked then...
if (checked.get(item.getId()))
{
// Add product to list of products to be compared.
compareProducts.add(item);
}
}
}
if(compareProducts.isEmpty())
{
// Error message that is displayed in the 'ErrorPage.xhtml' file.
errorMessage = "No Products selected to compare specifications. Select two or more products by ticking the check box in the second column 'Cmpr'";
return "process_ErrorPage";
}
// Rest of code to get product specification data ready to be displayed.
return "process_CompareSelected";
}
public String clearSelections()
{
// Untick all checkbox selections.
checked.clear();
return "process_MainSearchResult";
}
In the JSF Web page 'MainSearchResult.xhtml':在 JSF 网页“MainSearchResult.xhtml”中:
<h:commandLink action="#{productSelection.compareSelectedProducts()}" value="Cmpr Specification Comparison Table" />
<h:commandLink action="#{productSelection.clearSelections()}" value="Clear Selected" />
<h:dataTable value="#{productSelection.products}" rows="#{productSelection.numberRowsToDisplay}" first="#{productSelection.rowStart}" var="item" headerClass="table-header" >
<h:column>
<f:facet name="header">
<h:outputText style="font-size:12px" value="Cmpr" />
</f:facet>
<div style="text-align:center;" >
<h:selectBooleanCheckbox value="#{productSelection.checked[item.id]}" />
</div>
</h:column>
</h:dataTable>
In the 'faces-config.xml' file:在“faces-config.xml”文件中:
<navigation-rule>
<navigation-case>
<from-outcome>process_MainSearchResult</from-outcome>
<to-view-id>/MainSearchResult.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>process_CompareSelected</from-outcome>
<to-view-id>/CompareSelected.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<navigation-case>
<from-outcome>process_ErrorPage</from-outcome>
<to-view-id>/ErrorPage.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
One way to send in a parameter via <h:selectBooleanCheckbox>
is to send it in via the title of the Checkbox.通过
<h:selectBooleanCheckbox>
发送参数的一种方法是通过 Checkbox 的标题发送参数。 In the ValueChangeListener
, you can get it from the component using a getAttributes().get("title")
.在
ValueChangeListener
中,您可以使用getAttributes().get("title")
从组件中获取它。 This helps in cases where you want to send an id value as a parameter (as opposed to the selected row index).这在您希望将 id 值作为参数发送(而不是选定的行索引)的情况下很有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.