如何在 <h:dataTable> 或 <ui:repeat> 中使用 <h:selectBooleanCheckbox> 来选择多个项目?

Posted

技术标签:

【中文标题】如何在 <h:dataTable> 或 <ui:repeat> 中使用 <h:selectBooleanCheckbox> 来选择多个项目?【英文标题】:How to use <h:selectBooleanCheckbox> in <h:dataTable> or <ui:repeat> to select multiple items? 【发布时间】:2011-02-01 05:50:29 【问题描述】:

我有一个带有&lt;h:dataTable&gt; 的 Facelets 页面。在每一行中都有一个&lt;h:selectBooleanCheckbox&gt;。如果选中复选框,则应在 bean 中设置相应行后面的对象。

    我该怎么做? 如何在 backing bean 中获取选定的行或它们的数据? 还是使用&lt;h:selectManyCheckbox&gt; 会更好?

【问题讨论】:

【参考方案1】:

最好的办法是将h:selectBooleanCheckbox 值与Map&lt;RowId, Boolean&gt; 属性绑定,其中RowId 表示行标识符的类型。举个例子,你有一个Item 对象,它的标识符属性idLong

<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 Item 
    private Long id;
    // ...

public class Bean 
    private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
    private List<Item> items;

    public void submit() 
        List<Item> checkedItems = checked.entrySet().stream()
            .filter(Entry::getKey)
            .map(Entry::getValue)
            .collect(Collectors.toList());

        checked.clear(); // If necessary.

        // Now do your thing with checkedItems.
    

    // ...

您看,映射自动填充所有表项的id 作为键,复选框值自动设置为与项目id 关联的映射值作为键。

【讨论】:

使用&lt;Long, Item&gt; 类型的Map 会不会更容易,因此您只需要迭代地图而不是整个列表吗? @Markus:这是不可能的。 &lt;h:selectBooleanCheckbox&gt; 仅支持 booleanBoolean 值。 数据表和按钮应该是同一种形式吗?您能否发布更多关于视图方面的详细信息,或者只有按钮应该在表单中。 @Msaleh:当然它必须是相同的形式。您想在按下按钮时发送复选框值,对吧? 关于submit() 方法:filter()Predicate 作为返回booleangetKey() 返回Long 的参数,同样使用.map(Entry::getValue) 你将得到List&lt;Boolean&gt;。这应该是相反的:List&lt;Long&gt; checkedItems = checked.entrySet().stream() .filter(Entry::getValue) .map(Entry::getKey) .collect(Collectors.toList()); 吗?【参考方案2】:

通过&lt;h:selectBooleanCheckbox&gt; 发送参数的一种方法是通过复选框的标题发送参数。在ValueChangeListener 中,您可以使用getAttributes().get("title") 从组件中获取它。这在您希望将 id 值作为参数发送(而不是选定的行索引)的情况下很有帮助。

【讨论】:

我不确定您所说的“与选定的行索引相反”是什么意思,但如果您的目标是我的答案,那么请注意,我无处传递行索引。只是所选项目本身的 ID。【参考方案3】:

在以下示例中,我使用复选框来选择两个或多个产品,以允许用户使用 JSF 2.0 在新网页上比较产品规格。

我花了很长时间才找到以下问题(当然现在很明显)所以认为对于那些尝试使用上面的 BalusC 代码使用分页的人来说值得一提(很好的答案 BalusC,比我想象的要简单得多是)。

如果您使用分页,您将在该行获得空指针:

if (checked.get(item.getId()))

-在上面 BalusC 的代码中。

这是因为只有显示的复选框才会添加到地图中(doh;拍前额)。 对于那些复选框从不显示的产品,由于分页,此行将导致空指针错误,需要添加一个检查以忽略这些空指针(假设在页面加载时所有复选框都未选中)。为了让用户勾选一个复选框,他们需要显示分页页面,以便之后一切正常。

如果需要在第一个页面加载时勾选部分或全部复选框,那么这对您没有帮助...您必须手动将它们添加到地图中才能正确显示在页面加载时。

注意:因为我使用的是 JPA '来自数据库的实体类' 对象,所以我还需要在我的 ProductTbl 实体类中使用 @Transient 作为 ID,因为默认情况下,所有变量都被 JPA 视为数据库中的列,除非有前缀与@Transient。此外,我正在使用第二个链接来重置复选框,该链接调用 clearSelections(),我的“提交”是调用 compareSelectedProducts() 的链接,而不是提交按钮。

完整代码如下:

在从数据库派生的“ProductTbl”实体类中:

@Transient
private Long id;

public Long getId()

    return id;


public void setId(Long id)

    this.id = id;

在支持 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";

在 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>

在“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>

【讨论】:

以上是关于如何在 <h:dataTable> 或 <ui:repeat> 中使用 <h:selectBooleanCheckbox> 来选择多个项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 h:dataTable 中实现行编号

如何正确使用带有 h:dataTable 的 ResultSet

在 h:dataTable 中使用 java.util.Map

h:commandButton 在 h:dataTable 中不起作用

使用带有Primefaces DynaForms的dataTable

在 jsf<h:datatable 上在丰富的 fcaes 4 中实现 jquery