rich:datatable rowspan问题

时间:2010-01-08 16:19:59

标签: java jsf java-ee richfaces jstl

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

我有一个拥有Product对象集合的类公司。我想显示下表:

alt text

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

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

干杯!

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

  • 如果产品是空的(公司还没有产品),我打印两列。我通过将呈现的属性设置为#{myFuncs:sizeOf(company.products)}
  • 来有条件地执行此操作
  • 如果产品> = 1,那么我用 迭代它们,并在该循环内插入两列(一个用于产品名称,一个用于描述),以及每个产品名称列除外第一个我将 breakBefore 属性设置为#{!myFunc:firstProduct(company.products,product)} ,对于除第一个产品名称以外的所有产品名称,其评估结果为true

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

有没有办法实现行距,或者我是否在墙上敲头?

更新2: 该问题可能与此article有关,表明迭代组件之间的差异,例如< a4j:重复> 和标签< C:的forEach> 即可。第一个在渲染时发生,而第二个在渲染时运行,当JSF组件放在页面的组件树上时。

我试图获得富有:a4j之外的列:重复并且它们被渲染(当然,不是预期的,但它们确实如此)。

3 个答案:

答案 0 :(得分:6)

你可以在没有那些复杂的forEachs的情况下做到这一点。您只需要利用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

答案 1 :(得分:2)

遗憾的是,JSF UIData组件中没有rowpan支持。最好的方法是在相同行中显示产品集合。您可以使用其他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,使其看起来像rowpans。

答案 2 :(得分:0)

好的,基于上次更新,使用 c:forEach (构建组件树时)创建了执行迭代的页面。我提供的解决方案有效,但有些事情是错误的,因为:

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

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

<rich:dataTable width="70%" 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>