【问题标题】:Conditionally display row using JSF Datatable使用 JSF Datatable 有条件地显示行
【发布时间】:2011-02-19 05:50:39
【问题描述】:

我有一些当前可以工作的 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 时会生成一个空单元格。但我想在某些情况下跳过整行显示 - 我该怎么做?

【问题讨论】:

    标签: jsf datatable


    【解决方案1】:

    通过在所有&lt;h:column&gt; 标签中放置一个渲染属性,我成功地隐藏了行。问题是它抑制了表格标题。如果您的表格没有表格标题(它们是嵌入在&lt;h:column&gt; 中的&lt;f:facet name="header"&gt; 标签),这种方法可能适合您。

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

    【讨论】:

    • 试过这个,除非我做错了所有列都呈现解析为FALSE的行,仍然呈现为空行(即&lt;tr&gt;&lt;/tr&gt;
    【解决方案2】:

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

    https://stackoverflow.com/a/19177424

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

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

    【讨论】:

      【解决方案3】:

      我扩展 HtmlTableRenderer 默认渲染器并覆盖 renderRowStart 方法,通过将 style 属性赋予 table- >tr 元素,值为 display:none

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

      顺便说一句,在这个自定义渲染器中也有类似 PrimeFaces 实现的函数,它在表为空时给出消息,并且 table->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;
      }
      

      }

      【讨论】:

      • 在我之前的cmets中忘记提及了。我们需要将以下新元素添加到 faces-config.xml &lt;render-kit&gt; &lt;renderer&gt; &lt;component-family&gt;javax.faces.Data&lt;/component-family&gt; &lt;renderer-type&gt;javax.faces.Table&lt;/renderer-type&gt; &lt;renderer-class&gt;xxx.xxx.MyDataTableRenderer &lt;/renderer-class&gt; &lt;/renderer&gt; &lt;/render-kit&gt; @Laila Agaev
      【解决方案4】:

      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>
      

      【讨论】:

        【解决方案5】:

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

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

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

        示例是使用接缝 EL!

        【讨论】:

        • 我不明白这是如何工作的,您对列过滤器表达式的设置但行消失了吗?
        【解决方案6】:

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

        或者,您可以将rowClasses 参数用于dataTable。

        豆码:

        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;}
        

        【讨论】:

        • 抱歉,这不是一个真正的选项 - 此表显示某些应用程序范围的参考数据,除非在此特定情况下,数据只能在某些条件下显示。
        • 那么两个集合,一个包含所有数据,第二个包含用于显示的内容?
        • 问题是我有 2 行,根据情况,有时会显示 A 行,有时会显示 B 行,有时会同时显示两者。保留多套意味着我必须保留三个版本,这并不理想。我希望有另一种方法可以做到这一点。
        • 它仍然只有 2 个集合,您只需根据需要更改显示集合的内容。但是,如果您不介意在您的 M 中添加一个小 V,则可以通过单个集合以编程方式执行此操作。上面已编辑。
        • 纳加纳尔夫是对的。在 bean 级别过滤它。遍历主要的List 并仅收集另一个List 中感兴趣的条目。它不应该那么贵,因为 List 只包含引用。
        猜你喜欢
        • 2015-03-19
        • 2010-11-27
        • 2011-05-15
        • 1970-01-01
        • 2014-08-28
        • 1970-01-01
        • 2016-05-16
        相关资源
        最近更新 更多