使用JSF Datatable有条件地显示行

时间:2010-05-13 18:58:49

标签: jsf datatable

我有一些当前可用的JSF代码(如下所示),我需要修改它以有条件地禁止显示表的某些行。我知道如何有条件地抑制特定单元格的显示,但这似乎创建了一个空单元格,而我正在尝试做的是根本不显示该行。

有什么建议吗?

<h:dataTable styleClass="resultsTable" id="t1" value="#{r.common}" var="com" headerClass="headerBackgrnd" rowClasses="rowOdd, rowEven" columnClasses="leftAlign, rightAlign, leftAlign">
    <h:column>
        <h:outputText rendered="#{com.rendered}" styleClass="inputText" value="#{com.description}: " />
    </h:column>
    <h:column>
        <h:outputText styleClass="outputText" value="#{com.v1}" />
    </h:column>
    <h:column>
        <h:inputText styleClass="inputText" value="#{com.v2}" />
   </h:column>
</h:dataTable>

基本上,#{com.rendered}行会有条件地显示单个单元格的内容,当com.rendered为false时会生成一个空单元格。但是我想在某些条件下跳过显示器的整行 - 我该怎么做呢?

6 个答案:

答案 0 :(得分:13)

行对应于表集合中的数据对象。如果您不想要该行,请不要将该对象放入集合中。

或者,您可以对dataTable使用rowClasses参数。

Bean代码:

public String getRowClasses() {
    StringBuilder sb = new StringBuilder();
    for (Data data : myData) {
        sb.append(data.hide ? 'hide,' : 'show,');
    }
    return sb.toString();
}

CSS:

tr.hide {display:none;}

答案 1 :(得分:5)

对于使用richFaces的人,您可以使用rich:column的filterExpression属性。

<rich:column filterExpression="#{put your expression here}">
    ...
</rich>

如果不满足条件,则过滤掉完整的行。

示例是使用seam EL!

答案 2 :(得分:2)

Brian的解决方案的扩展。 为了显示列名,我在primefaces中执行了以下操作

<p:dataTable value="#{eiBean.dce.ilDbConns}" var="c">
    <p:columnGroup type="header">
        <p:row>
            <p:column colspan="1" />
            <p:column colspan="1" />
        </p:row>
        <p:row>
            <p:column headerText="DataBase Type" width="auto" />
            <p:column headerText="URL" width="400" />
        </p:row>
    </p:columnGroup>
    <p:column rendered='#{c.conType == "TARGET"}'>
        <p:outputLabel value="#{c.dbType}" />
    </p:column>
    <p:column rendered='#{c.conType == "TARGET"}'>
        <p:outputLabel value="#{c.dbUrl}" />
    </p:column>         
</p:dataTable>

答案 3 :(得分:0)

我通过在所有<h:column>标记中放置渲染属性来成功隐藏行。问题是它会抑制表头。如果您的表格没有表格标题(<f:facet name="header">中嵌入<h:column>个标记),则此方法可能对您有效。

我最终在支持bean中使用了多个列表,因为我需要表头。

答案 4 :(得分:0)

我扩展 HtmlTableRenderer 默认渲染器并覆盖 renderRowStart 方法,通过将 样式 属性赋予表格来实现此目的 - &gt; tr元素的值为 display:none

绑定列表中的项需要实现TableRow接口,该接口只有一个isHide方法。在具体类中,您可以放置​​任何您喜欢的逻辑来给出一个布尔值。

BTW,在这个自定义渲染器中还有PrimeFaces实现,就像函数一样,当表为空时给出消息,table-&gt; tr将自动计算表中的列数并为colspan属性赋予适当的值。

public class MyDataTableRenderer extends HtmlTableRenderer {
    private static final Integer[] ZERO_INT_ARRAY = new Integer[] { 0 };
    private static final String NO_RESULT_MESSAGE_ATTR_NAME = "noResultMessage";
    private static final String defaultEmptyMessage = "No records found";
    private static final Logger log = Logger.getLogger(DHSDataTableRenderer.class.getName());

@Override
public void encodeInnerHtml(FacesContext facesContext, UIComponent component) throws IOException {
    UIData uiData = (UIData) component;
    String message = (String) uiData.getAttributes().get(NO_RESULT_MESSAGE_ATTR_NAME);
    if (message == null || "".equals(message.trim())) {
        message = defaultEmptyMessage;
    }

    ResponseWriter writer = facesContext.getResponseWriter();

    int rowCount = uiData.getRowCount();

    int newspaperColumns = getNewspaperColumns(component);

    int columnNumber = getChildCount(component);

    if (rowCount == -1 && newspaperColumns == 1) {
        encodeInnerHtmlUnknownRowCount(facesContext, component);
        return;
    }

    if (rowCount == 0) {
        // nothing to render, to get valid xhtml we render an empty dummy
        // row
        writer.startElement(HTML.TBODY_ELEM, uiData);
        writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element", null);
        writer.startElement(HTML.TR_ELEM, uiData);
        writer.startElement(HTML.TD_ELEM, uiData);
        writer.writeAttribute(HTML.COLSPAN_ATTR, columnNumber, null);
        writer.writeAttribute(HTML.CLASS_ATTR, "dhs-empty-table", null);
        writer.write(message);
        writer.endElement(HTML.TD_ELEM);
        writer.endElement(HTML.TR_ELEM);
        writer.endElement(HTML.TBODY_ELEM);
        return;
    }

    // begin the table
    // get the CSS styles
    Styles styles = getStyles(uiData);

    int first = uiData.getFirst();
    int rows = uiData.getRows();
    int last;

    if (rows <= 0) {
        last = rowCount;
    } else {
        last = first + rows;
        if (last > rowCount) {
            last = rowCount;
        }
    }

    int newspaperRows;
    if ((last - first) % newspaperColumns == 0) {
        newspaperRows = (last - first) / newspaperColumns;
    } else {
        newspaperRows = ((last - first) / newspaperColumns) + 1;
    }
    boolean newspaperHorizontalOrientation = isNewspaperHorizontalOrientation(component);

    // get the row indizes for which a new TBODY element should be created
    Integer[] bodyrows = getBodyRows(facesContext, component);
    int bodyrowsCount = 0;

    // walk through the newspaper rows
    for (int nr = 0; nr < newspaperRows; nr++) {
        boolean rowStartRendered = false;
        // walk through the newspaper columns
        for (int nc = 0; nc < newspaperColumns; nc++) {

            // the current row in the 'real' table
            int currentRow;
            if (newspaperHorizontalOrientation) {
                currentRow = nr * newspaperColumns + nc + first;
            } else {
                currentRow = nc * newspaperRows + nr + first;
            }

            // if this row is not to be rendered
            if (currentRow >= last) {
                continue;
            }

            // bail if any row does not exist
            uiData.setRowIndex(currentRow);
            if (!uiData.isRowAvailable()) {
                log.severe("Row is not available. Rowindex = " + currentRow);
                break;
            }

            if (nc == 0) {
                // first column in table, start new row
                beforeRow(facesContext, uiData);

                // is the current row listed in the bodyrows attribute
                if (ArrayUtils.contains(bodyrows, currentRow)) {
                    // close any preopened TBODY element first
                    if (bodyrowsCount != 0) {
                        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
                        writer.endElement(HTML.TBODY_ELEM);
                    }
                    HtmlRendererUtils.writePrettyLineSeparator(facesContext);
                    writer.startElement(HTML.TBODY_ELEM, uiData);
                    // Do not attach bodyrowsCount to the first TBODY
                    // element, because of backward compatibility
                    writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element" + (bodyrowsCount == 0 ? "" : bodyrowsCount),
                            null);
                    bodyrowsCount++;
                }

                HtmlRendererUtils.writePrettyLineSeparator(facesContext);
                renderRowStart(facesContext, writer, uiData, styles, nr);
                rowStartRendered = true;
            }

            List<UIComponent> children = null;
            for (int j = 0, size = getChildCount(component); j < size; j++) {
                if (children == null) {
                    children = getChildren(component);
                }
                UIComponent child = children.get(j);
                if (child.isRendered()) {
                    boolean columnRendering = child instanceof UIColumn;

                    if (columnRendering) {
                        beforeColumn(facesContext, uiData, j);
                    }

                    encodeColumnChild(facesContext, writer, uiData, child, styles, nc * uiData.getChildCount() + j);

                    if (columnRendering) {
                        afterColumn(facesContext, uiData, j);
                    }
                }
            }

            if (hasNewspaperTableSpacer(uiData)) {
                // draw the spacer facet
                if (nc < newspaperColumns - 1) {
                    renderSpacerCell(facesContext, writer, uiData);
                }
            }
        }
        if (rowStartRendered) {
            renderRowEnd(facesContext, writer, uiData);
            afterRow(facesContext, uiData);
        }
    }

    if (bodyrowsCount != 0) {
        // close the last TBODY element
        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        writer.endElement(HTML.TBODY_ELEM);
    }
}

@Override
protected void renderRowStart(FacesContext facesContext, ResponseWriter writer, UIData uiData, Styles styles, int rowStyleIndex) throws IOException {
    writer.startElement(HTML.TR_ELEM, null); // uiData);

    renderRowStyle(facesContext, writer, uiData, styles, rowStyleIndex);
    Object obj = uiData.getRowData();
    boolean isHide = false;
    if (obj instanceof TableRow) {
        isHide = ((TableRow) obj).isHide();
    }
    if (isHide) {
        writer.writeAttribute("style", "display: none;", null);
    }
    Object rowId = uiData.getAttributes().get(org.apache.myfaces.shared.renderkit.JSFAttr.ROW_ID);

    if (rowId != null) {
        writer.writeAttribute(HTML.ID_ATTR, rowId.toString(), null);
    }
}

private void encodeInnerHtmlUnknownRowCount(FacesContext facesContext, UIComponent component) throws IOException {
    UIData uiData = (UIData) component;
    ResponseWriter writer = facesContext.getResponseWriter();

    Styles styles = getStyles(uiData);

    Integer[] bodyrows = getBodyRows(facesContext, component);
    int bodyrowsCount = 0;

    int first = uiData.getFirst();
    int rows = uiData.getRows();
    int currentRow = first;
    boolean isRowRendered = false;

    while (true) {
        uiData.setRowIndex(currentRow);
        if (!uiData.isRowAvailable()) {
            break;
        }

        isRowRendered = true;

        // first column in table, start new row
        beforeRow(facesContext, uiData);

        // is the current row listed in the bodyrows attribute
        if (ArrayUtils.contains(bodyrows, currentRow)) {
            // close any preopened TBODY element first
            if (bodyrowsCount != 0) {
                HtmlRendererUtils.writePrettyLineSeparator(facesContext);
                writer.endElement(HTML.TBODY_ELEM);
            }
            HtmlRendererUtils.writePrettyLineSeparator(facesContext);
            writer.startElement(HTML.TBODY_ELEM, uiData);
            // Do not attach bodyrowsCount to the first TBODY element,
            // because of backward compatibility
            writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element" + (bodyrowsCount == 0 ? "" : bodyrowsCount), null);
            bodyrowsCount++;
        }

        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        renderRowStart(facesContext, writer, uiData, styles, currentRow);

        List<UIComponent> children = null;
        for (int j = 0, size = getChildCount(component); j < size; j++) {
            if (children == null) {
                children = getChildren(component);
            }
            UIComponent child = children.get(j);
            if (child.isRendered()) {
                boolean columnRendering = child instanceof UIColumn;

                if (columnRendering) {
                    beforeColumn(facesContext, uiData, j);
                }

                encodeColumnChild(facesContext, writer, uiData, child, styles, j);

                if (columnRendering) {
                    afterColumn(facesContext, uiData, j);
                }
            }
        }

        renderRowEnd(facesContext, writer, uiData);
        afterRow(facesContext, uiData);

        currentRow++;

        if (rows > 0 && currentRow - first > rows) {
            break;
        }
    }

    if (!isRowRendered) {
        // nothing to render, to get valid xhtml we render an empty dummy
        // row
        writer.startElement(HTML.TBODY_ELEM, uiData);
        writer.writeAttribute(HTML.ID_ATTR, component.getClientId(facesContext) + ":tbody_element", null);
        writer.startElement(HTML.TR_ELEM, uiData);
        writer.startElement(HTML.TD_ELEM, uiData);
        writer.endElement(HTML.TD_ELEM);
        writer.endElement(HTML.TR_ELEM);
        writer.endElement(HTML.TBODY_ELEM);
        return;
    }

    if (bodyrowsCount != 0) {
        // close the last TBODY element
        HtmlRendererUtils.writePrettyLineSeparator(facesContext);
        writer.endElement(HTML.TBODY_ELEM);
    }
}

private Integer[] getBodyRows(FacesContext facesContext, UIComponent component) {
    Integer[] bodyrows = null;
    String bodyrowsAttr = (String) component.getAttributes().get(JSFAttr.BODYROWS_ATTR);
    if (bodyrowsAttr != null && !"".equals(bodyrowsAttr)) {
        String[] bodyrowsString = StringUtils.trim(StringUtils.splitShortString(bodyrowsAttr, ','));
        // parsing with no exception handling, because of JSF-spec:
        // "If present, this must be a comma separated list of integers."
        bodyrows = new Integer[bodyrowsString.length];
        for (int i = 0; i < bodyrowsString.length; i++) {
            bodyrows[i] = new Integer(bodyrowsString[i]);
        }

    } else {
        bodyrows = ZERO_INT_ARRAY;
    }
    return bodyrows;
}

}

答案 5 :(得分:0)

使用此处建议的空css选择器,但使用tr而不是td。这对我有用。

https://stackoverflow.com/a/19177424

如此处所述:https://developer.mozilla.org/en-US/docs/Web/CSS/:empty 此选择器适用于所有当前浏览器。

<style>
  tr:empty {
    display: none;
  }
</style>