丰富:数据表行跨度问题

Posted

技术标签:

【中文标题】丰富:数据表行跨度问题【英文标题】:rich:datatable rowspan issue 【发布时间】:2011-01-02 23:48:14 【问题描述】:

我需要创建一个 Rich:dataTable(甚至是扩展的)具有以下功能:

我有一个 Company 类,其中包含 Product 对象的集合。我想显示下表:

我仍然没有弄清楚如何使用子表来做到这一点(在所有示例中,我发现子表与主表具有完全相同的列)。据推测,我需要在前两列中使用行跨度,但我仍然没有找到方法。

有人可以为此提供伪代码吗?

干杯!

更新 1: 我尝试将左侧列的 rowspan 设置为列表或产品的大小,然后:

如果产品是空的(公司还没有产品),我打印两列。我通过将它们的 rendered 属性设置为 #myFuncs:sizeOf(company.products) 有条件地做到这一点 如果产品 >= 1,则使用 对其进行迭代,并在该循环内插入两列(一列用于产品名称,一列用于描述),并且对于每个产品名称列,除了第一个我将 breakBefore 属性设置为 # !myFunc:firstProduct(company.products, product),它对除第一个以外的所有产品名称的计算结果为 true。

不幸的是,这对我不起作用,因为 a4j:repeat 内的列根本没有出现 - 不是因为 rendered 标记。循环是正确的,因为如果我打印其他标准文本,它就会出现。

有没有办法实现行跨度,还是我把头撞到墙上了?

更新 2: 问题大概和这个article有关,说明等迭代组件和标签的区别。第一个发生在渲染时,而第二个操作更早,当 JSF 组件被放置到页面的组件树上时。

我尝试在 a4j:repeat 之外获取 rich:columns 并且它们被渲染(当然,不像预期的那样,但确实如此)。

【问题讨论】:

【参考方案1】:

很遗憾,JSF UIData 组件中不支持行跨度。您能做的最好的事情就是在 same 行中显示产品集合。您可以使用另一个UIData 组件来迭代它,例如h:dataTable(渲染<table>)、t:dataList(渲染<ul>)或a4j:repeat(不渲染任何内容,您需要在每个之后使用例如<br/>项目)。

基于基本JSF组件的半伪:

<h:dataTable value="#bean.companies" var="company">
    <h:column>
        <h:outputText value="#company.name" />
    </h:column>
    <h:column>
        <h:outputText value="#company.email" />
    </h:column>
    <h:column>
        <h:dataTable value="#company.products" var="product">
            <h:column>
                <h:outputText value="#product.name" />
            </h:column>
        </h:dataTable>
    </h:column>
    <h:column>
        <h:dataTable value="#company.products" var="product">
            <h:column>
                <h:outputText value="#product.description" />
            </h:column>
        </h:dataTable>
    </h:column>
</h:dataTable>

以聪明的方式使用 CSS,让它看起来像行跨度。

【讨论】:

谢谢伙计。我认为也许我可以使用 rich:extendedDataTable 来完成我需要做的事情。它有一个名为“按列分组行”的功能,但缺点是我只能按一列分组。你认为另一个组件库(即 Icefaces)有一个数据表可以满足我的需要吗?干杯! 抱歉,不能说太多。我只有在 Mojarra 和 Tomahawk 方面的丰富经验,在 RichFaces/Ajax4jsf 方面只有一点经验。 此外,RichFaces 数据表确实 具有列的 rowspan 属性。我还没有找到使用它来做我想做的特定事情的方法。【参考方案2】:

好的,基于上次更新,创建了使用 c:forEach 进行迭代的页面(同时构建组件树)。我提供的解决方案有效,但感觉有些不对劲,因为:

花费了太多时间(对于大约 20 家公司和 200 种产品,大约 3 秒 100% CPU)。我怀疑这是因为 for c:forEach 循环本质上构建了一个必须渲染的巨大组件树,而不是组件树小得多的初始方法。 我认为我必须针对数据的每次更改重新构建整个组件树,而不是仅仅重新渲染它。

无论如何,代码。我所做的是这样的(没有测试过下面的,但你会得到图片。请注意,rich:dataTable 中的迭代基本上被忽略了):

<rich:dataTable  id="applicantsTable" rows="100"
rowClasses="applicant_row" columnClasses="col"
value="#backingBean.companyList" var="company">
<f:facet name="header">
        <rich:column>
            <h:outputText styleClass="headerText" value="Company Name" />
        </rich:column>
        <rich:column>
            <h:outputText styleClass="headerText" value="Company Email" />
        </rich:column>
        <rich:column>
            <h:outputText styleClass="headerText" value="Product Name" />
        </rich:column>
        <rich:column>
            <h:outputText styleClass="headerText" value="Product Email" />
        </rich:column>

</f:facet>

<c:forEach items="#backingBean.companyList" var="c_company">

    <c:if test="#prs:collectionSize(c_company.products)> 0">

        <rich:column breakBefore="true"
            rowspan="#prs:collectionSize(c_company.products)">
            <h:outputText value="#c_company.name" />
        </rich:column>

        <rich:column
            rowspan="#prs:collectionSize(c_company.products)">
            <h:outputText value="#c_company.email" />
        </rich:column>

        <c:forEach items="#c_company.products" var="c_product">
            <!-- This if clause is just to determine the breakBefore attribute -->
            <c:if test="#c_company.products[0] == c_product">
                <rich:column>
                    <h:outputText value="#c_product.name" />
                </rich:column>
            </c:if>

            <c:if test="#c_company.products[0] != c_product">
                <rich:column breakBefore="true" styleClass="internal_cell">
                    <h:outputText value="#c_product.name" />
                </rich:column>
            </c:if>

            <rich:column styleClass="internal_cell">
                <h:outputText value="#c_product.email" />
            </rich:column>

        </c:forEach>

    </c:if>

</c:forEach>

【讨论】:

你也可以只做基本的 EL #not empty bean.collection 和 JSTL 的 #fn:length(bean.collection) 而不是 prs:collectionSize【参考方案3】:

您可以在没有那些复杂的 forEach 的情况下做到这一点。您只需要利用 subTable 和 rowKeyVar。

例如:

<rich:dataTable
    value="#backingBean.companyList"
    rows="100"
    var="company">
    <f:facet name="header">
        <rich:columnGroup>
            <rich:column>Company Name</rich:column>
            <rich:column>Company Email</rich:column>
            <rich:column>Product Name</rich:column>
            <rich:column>Product Email</rich:column>
        </rich:columnGroup>
    </f:facet>
    <rich:subTable value="#company.products" var="product" rowKeyVar="rowKey">
        <rich:column rowspan="#company.products.size()" rendered="#rowKey eq 0">
            #company.name
        </rich:column>
        <rich:column rowspan="#company.products.size()" rendered="#rowKey eq 0">
            #company.email
        </rich:column>
        <rich:column>
            #product.name
        </rich:column>
        <rich:column>
            #product.email
        </rich:column>
    </rich:subTable>
</rich:dataTable>

对我来说完美呈现。请注意,我正在使用具有 Jboss Extended EL 的 Seam,它允许我在集合上调用 size()。如果你不使用它,你可以使用 prs:collectionSize() 或 fn:length() 作为替代。

这也适用于 Richfaces 数据滚动条。

希望这会有所帮助。

D.

【讨论】:

我正在尝试这个。 但是它只显示拥有产品的公司。有一些公司没有产品,我想出现(剩下的产品栏应该是空的)。有支持吗? 不使用这种方法。这就是限制。但是,您可以通过对公司进行后处理并在不存在的地方添加空白产品来伪造行。 我继续讨论 Richfaces 社区:community.jboss.org/message/541744。在那里,我们找到了一种解决方法,即使对于没有产品的公司也是如此。

以上是关于丰富:数据表行跨度问题的主要内容,如果未能解决你的问题,请参考以下文章

具有行跨度的 Primefaces 数据表

使用行跨度动态呈现数据

angularjs中json数据的行跨度

vue.js 使用行跨度渲染表

Firefox 打印多页行跨度

使用 jquery 将行跨度添加到每行的第一个 td