4 Replies Latest reply on Sep 19, 2012 11:22 PM by snjv180

    Sort & Filter using ExtendedDataModel/Arrangeable affecting all other Data Iteration components in same page

    cseabra

      Hi,

       

      I'm using RichFaces 4.2.2.FINAL

       

      If you put more than one data component iteration (extendeddatatable in this case) on the same page making use sorting and filtering, when user uses sorting / filtering of these components all others are affected.

       

      I noticed because the "arrange" method from all components is always called.

       

      The question is: Is this normal behavior? I ask because it is not feasible to reload all the data iteration components whenever a change occurs in any of them.

       

      Thanks!

        • 1. Re: Sort & Filter using ExtendedDataModel/Arrangeable affecting all other Data Iteration components in same page
          snjv180

          I think you may use limitrender attribute to stop this behaviour. I think you may be rendering a parent component and this has made changes to all of the child components as well.

          • 2. Re: Sort & Filter using ExtendedDataModel/Arrangeable affecting all other Data Iteration components in same page
            cseabra

            I put limitrender where possible and the result was still the same.

             

            See my code:

             

            index.xhtml

            <?xml version="1.0" encoding="UTF-8" ?>

            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

            <ui:composition xmlns="http://www.w3.org/1999/xhtml"

            xmlns:h="http://java.sun.com/jsf/html"

            xmlns:f="http://java.sun.com/jsf/core"

            xmlns:fn="http://java.sun.com/jsp/jstl/functions"

            xmlns:c="http://java.sun.com/jsp/jstl/"

            xmlns:ui="http://java.sun.com/jsf/facelets"

            xmlns:a4j="http://richfaces.org/a4j"

            xmlns:rich="http://richfaces.org/rich" template="/templates/main.xhtml">

            <ui:define name="content">

              <h:form id="formBooking">

              <rich:popupPanel id="panelModal" width="350" height="100"

              modal="true">

              <f:facet name="header">

              <h:panelGroup>

              <h:outputText value="Editando ..."></h:outputText>

              </h:panelGroup>

              </f:facet>

              <f:facet name="controls">

              <h:graphicImage library="default" name="img/close.png"

              style="cursor:pointer"

              onclick="#{rich:component('panelModal')}.hide()" />

              </f:facet>

              <h:outputText value="Será implementado em breve"></h:outputText>

              </rich:popupPanel>

             

              <a4j:outputPanel ajaxRendered="true">

              <h:messages />

              </a4j:outputPanel>

             

              <div class="box-search">

              <h:panelGrid columns="6">

              <h:outputText value="CLIENTE" />

             

              <h:inputText id="cadimpCode" size="8"

              value="#{bookingController.cadimpCode}" readonly="true" />

             

              <rich:autocomplete id="autoCompleteName"

              autocompleteMethod="#{bookingController.loadCadimpsByName}"

              var="cadimpName" converter="cadimpConverter"

              fetchValue="#{cadimpName}" minChars="4"

              value="#{bookingController.selectedCadimp}"

              onselectitem="selectingCadimp()" style="margin:2px;padding:1px;"

              inputClass="autocomplete-cadimp"

              popupClass="autocomplete-cadimp-popup">                               

                                                                ${cadimpName}

                                                  </rich:autocomplete>

              <a4j:jsFunction name="selectingCadimp" execute="autoCompleteName"

              render="cadimpCode" />

             

              <a4j:commandButton value="Pesquisar"

              action="#{bookingController.setLoadBookinksToTrue}">

              <a4j:ajax event="click" render="panelTabs previsao atracadas" execute="@this" limitRender="true"/>

              </a4j:commandButton>

             

                                                              <h:button value="Limpar" />

              </h:panelGrid>

                                          </div>

             

              <rich:panel id="panelTabs"

              style="border: 0px; margin: 0px; padding: 0px;">

              <rich:tabPanel id="tabs">

              <rich:tab header="Pesquisar" headerStyle="padding: 5px;">

                                                                        <f:facet name="header">

              <h:graphicImage library="default" name="img/find.png" />

              </f:facet>

              </rich:tab>

              <!-- ======= PREVISAO DE EMBARQUE ======= -->

              <rich:tab

              header="PREVISÃO DE EMBARQUE(#{bookingController.bookingsPrevisaoDeEmbarqueTabRowCount})"

              headerStyle="padding: 5px;">

              <ui:include src="includes/bookingTable.xhtml">

              <ui:param name="bookings"

              value="#{bookingController.bookingsPrevisaoDeEmbarqueTab}" />

              <ui:param name="tableId" value="previsao" />

              <ui:param name="sortOrder"

              value="#{bookingController.sortOrdersPrevisaoDeEmbarque}" />

              </ui:include>

              </rich:tab>

             

              <!-- ======= CARGAS EMBARCADAS ======= -->

              <rich:tab

              header="CARGAS EMBARCADAS(#{bookingController.bookingsCargasEmbarcadasTabRowCount})"

              headerStyle="padding: 5px;">

              <ui:include src="includes/bookingTable.xhtml">

              <ui:param name="bookings"

              value="#{bookingController.bookingsCargasEmbarcadasTab}"></ui:param>

              <ui:param name="tableId" value="embarcadas"></ui:param>

              <ui:param name="sortOrder"

              value="#{bookingController.sortOrdersCargasEmbarcadas}"></ui:param>

              </ui:include>

              </rich:tab>

              <!-- ======= CARGAS LIBERADAS ======= -->

              <rich:tab header="CARGAS LIBERADAS(X)" headerStyle="padding: 5px;"></rich:tab>

              <rich:tab header="IMPRIMIR" headerStyle="padding: 5px;">

                                                                        <f:facet name="header">

              <h:graphicImage library="default" name="img/printer.png" />

              </f:facet>

              </rich:tab>

              <rich:tab header="SALVAR" headerStyle="padding: 5px;">

                                                                        <f:facet name="header">

              <h:graphicImage library="default" name="img/disk.png" />

              </f:facet>

              </rich:tab>

              </rich:tabPanel>

              </rich:panel>

              </h:form>

            </ui:define>

            </ui:composition>

             

             

             

            bookingTable.xhtml:

            <?xml version="1.0" encoding="UTF-8" ?>

            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

            <ui:composition xmlns="http://www.w3.org/1999/xhtml"

            xmlns:h="http://java.sun.com/jsf/html"

            xmlns:f="http://java.sun.com/jsf/core"

            xmlns:fn="http://java.sun.com/jsp/jstl/functions"

            xmlns:c="http://java.sun.com/jsp/jstl/"

            xmlns:ui="http://java.sun.com/jsf/facelets"

            xmlns:a4j="http://richfaces.org/a4j"

            xmlns:rich="http://richfaces.org/rich">

             

            <rich:extendedDataTable  value="#{bookings}" var="bookingItem" rows="10"

              id="${tableId}">

              <rich:column>

              <h:commandLink>

              <h:graphicImage library="default" name="img/page_edit.png" />

              <rich:componentControl target="panelModal" operation="show" />

              </h:commandLink>

              </rich:column>

             

              <ui:param name="propertyRef" value="ref" />

              <rich:column sortBy="${propertyRef}"

              sortOrder="#{sortOrder[propertyRef]}">

              <f:facet name="header">

              <h:outputText value="REF" />

              <h:commandLink action="#{bookingController.toggleSort}">

                                       #{sortOrder[propertyRef]}

                                      <a4j:ajax render="${tableId}" execute="@this" limitRender="true"/>

                                      <f:setPropertyActionListener

              target="#{bookingController.sortProperty}" value="ref" />

              <f:setPropertyActionListener

              target="#{bookingController.currentSortOrder}" value="${sortOrder}" />

                                  </h:commandLink>

              </f:facet>

              <h:outputText value="#{bookingItem.ref}" />

              </rich:column>

             

              <ui:param name="propertyDtInformacao" value="dtInformacao" />

              <rich:column sortBy="#{propertyDtInformacao}"

              sortOrder="#{sortOrder[propertyDtInformacao]}">

              <f:facet name="header">

              <h:outputText value="ATUALIZACAO" />

              <h:commandLink action="#{bookingController.toggleSort}">

                                      #{sortOrder[propertyDtInformacao]}

                                      <a4j:ajax render="${tableId}" execute="@this"  limitRender="true"/>

                                      <f:setPropertyActionListener

              target="#{bookingController.sortProperty}" value="dtInformacao" />

              <f:setPropertyActionListener

              target="#{bookingController.currentSortOrder}" value="${sortOrder}" />

                                  </h:commandLink>

              </f:facet>

              <h:outputText value="#{bookingItem.dtInformacao}" />

              </rich:column>

             

              <f:facet name="footer">

              <rich:dataScroller for="${tableId}" limitRender="true" />

              </f:facet>

            </rich:extendedDataTable>

            </ui:composition>

             

             

            BaseHibernateExtendedDataModel.java

            package br.com.*******.web.datamodels;

             

            import java.util.List;

             

            import javax.el.ValueExpression;
            import javax.faces.context.FacesContext;

             

            import org.ajax4jsf.model.DataVisitor;
            import org.ajax4jsf.model.ExtendedDataModel;
            import org.ajax4jsf.model.Range;
            import org.ajax4jsf.model.SequenceRange;
            import org.hibernate.Criteria;
            import org.hibernate.criterion.MatchMode;
            import org.hibernate.criterion.Order;
            import org.hibernate.criterion.Projections;
            import org.hibernate.criterion.Restrictions;
            import org.richfaces.component.SortOrder;
            import org.richfaces.model.Arrangeable;
            import org.richfaces.model.ArrangeableState;
            import org.richfaces.model.FilterField;
            import org.richfaces.model.SortField;
            import org.slf4j.Logger;
            import org.slf4j.LoggerFactory;

             

            public class BaseHibernateExtendedDataModelextends IQueryAbleType, I extends Entitie>
                    extends ExtendedDataModel implements Arrangeable {
                private static Logger log = LoggerFactory
                        .getLogger(BaseHibernateExtendedDataModel.class);
                protected SequenceRange cachedRange;
                protected Integer cachedRowCount;
                protected List cachedItems;
                protected IQueryAbleType queryAbleType;
                protected Object[] restrictionsValues;

                private List filterFields;
                private List sortFields;

                private Object rowKey;

                public BaseHibernateExtendedDataModel(IQueryAbleType queryAbleType,
                        Object... restrictionsValues) {
                    super();
                    this.queryAbleType = queryAbleType;
                    this.restrictionsValues = restrictionsValues;
                }

                protected static boolean areEqualsRanges(SequenceRange range1,
                        SequenceRange range2) {
                    if (range1 == null || range2 == null)
                        return (range1 == null && range2 == null);
                    else
                        return (range1.getFirstRow() == range2.getFirstRow() && range1
                                .getRows() == range2.getRows());
                }

                @Override
                public Object getRowKey() {
                    return rowKey;
                }

                @Override
                public void setRowKey(Object arg0) {
                    rowKey = arg0;
                }

                @SuppressWarnings(\"unchecked\")
                @Override
                public void walk(FacesContext context, DataVisitor visitor, Range range,
                        Object argument) {
                    SequenceRange sequenceRange = (SequenceRange) range;
                    if (this.cachedItems == null
                            || !areEqualsRanges(this.cachedRange, sequenceRange)) {
                        Criteria criteria = this.queryAbleType
                                .getCriteria(this.restrictionsValues);
                        if (sequenceRange != null) {
                            int first = sequenceRange.getFirstRow();
                            int rows = sequenceRange.getRows();
                            criteria.setFirstResult(first);
                            if (rows > 0) {
                                criteria.setMaxResults(rows);
                            }
                            log.info(\"Specifying offset = \" + first + \" and limit = \"
                                    + rows);
                        }

                        appendSorts(context, criteria);
                        appendFilters(context, criteria);

                        this.cachedRange = sequenceRange;
                        log.info(\"Quering database\");
                        this.cachedItems = criteria.list();
                    }
                    for (I item : this.cachedItems) {
                        visitor.process(context, item.getId(), argument);
                    }

                }

                @Override
                public int getRowCount() {
                    if (this.cachedRowCount == null) {
                        Criteria criteria = queryAbleType
                                .getCriteria(this.restrictionsValues);
                        appendFilters(FacesContext.getCurrentInstance(), criteria);
                        log.info(\"Getting row count\");
                        this.cachedRowCount = ((Long) criteria.setProjection(
                                Projections.rowCount()).uniqueResult()).intValue();
                        log.info(\"cachedRowCount setted to \" + this.cachedRowCount);
                    }
                    return cachedRowCount;
                }

                @Override
                public I getRowData() {
                    for (I item : cachedItems) {
                        if (item.getId().equals(this.getRowKey()))
                            return item;
                    }
                    return null;
                }

                private int rowIndex;
                private ArrangeableState arrangeableState;

                @Override
                public int getRowIndex() {
                    return rowIndex;
                }

                @Override
                public boolean isRowAvailable() {
                    return (getRowData() != null);
                }

                @Override
                public void setRowIndex(int arg0) {
                    rowIndex = arg0;
                }

                @Override
                public void setWrappedData(Object arg0) {
                    throw new UnsupportedOperationException();
                }

                @Override
                public Object getWrappedData() {
                    throw new UnsupportedOperationException();
                }

                @Override
                public void arrange(FacesContext context, ArrangeableState state) {
                    if (state != null) {
                        //TODO
            //            if (arrangeableState != null) {
            //                if (stateAreEquals(arrangeableState, state)) {
            //                    return;
            //                }
            //            }

                        //arrangeableState = state;
                        filterFields = state.getFilterFields();
                        sortFields = state.getSortFields();
                        cachedItems = null;
                        cachedRange = null;
                        cachedRowCount = null;
                    }
                }

                private void appendFilters(FacesContext context, Criteria criteria) {
                    if (filterFields != null) {
                        for (FilterField filterField : filterFields) {
                            String propertyName = getPropertyName(context,
                                    filterField.getFilterExpression());
                            String filterValue = (String) filterField.getFilterValue();
                            if (filterValue != null && filterValue.length() != 0) {
                                log.info(\"Adding filter filterField\\\"\" + filterField
                                        + \"\\\", filterValue: \" + filterValue);
                                criteria.add(Restrictions.like(propertyName, filterValue,
                                        MatchMode.ANYWHERE).ignoreCase());
                            }
                        }
                    }
                }

                private void appendSorts(FacesContext context, Criteria criteria) {
                    if (sortFields != null) {
                        for (SortField sortField : sortFields) {
                            SortOrder ordering = sortField.getSortOrder();
                            if (SortOrder.ascending.equals(ordering)
                                    || SortOrder.descending.equals(ordering)) {
                                String propertyName = getPropertyName(context,
                                        sortField.getSortBy());
                                Order order = SortOrder.ascending.equals(ordering) ? Order
                                        .asc(propertyName) : Order.desc(propertyName);
                                log.info(\"Adding order:\" + order);
                                criteria.addOrder(order);
                            }
                        }
                    }
                }

                private static String getPropertyName(FacesContext context,
                        ValueExpression expression) {
                    return (String) ((ValueExpression) expression).getValue(context
                            .getELContext());
                }

            }
            • 3. Re: Sort & Filter using ExtendedDataModel/Arrangeable affecting all other Data Iteration components in same page
              cseabra

              I solve my problem implementing:

               

              stateAreEquals(ArrangeableState state1, ArrangeableState state2)

               

              and calling this in "arrange(FacesContext context, ArrangeableState state)"

               

               

                  public void arrange(FacesContext context, ArrangeableState state) {
                      if (state != null) {
                          if (arrangeableState != null) {
                              if (stateAreEquals(arrangeableState, state)) {
                                  return;
                              }
                          }

               

                          arrangeableState = state;
                          filterFields = state.getFilterFields();
                          sortFields = state.getSortFields();
                          cachedItems = null;
                          cachedRange = null;
                          cachedRowCount = null;
                      }
                  }
              • 4. Re: Sort & Filter using ExtendedDataModel/Arrangeable affecting all other Data Iteration components in same page
                snjv180

                Good to know that you solved it.

                 

                -Sanjeev