Board index JavaServer Faces General Filtering datatables loaded with ajax.

Filtering datatables loaded with ajax.

Components, Ajax Framework, Utilities and More.


Posts: 102
I'm having issues with filtering datatables that were not rendered in the initial page load but have been loaded later. This is a very basic example to show what I mean. We are also integrating with spring webflow so the problem could be there but I figured I would post it here to see if you guys have any idea what could be wrong.

PF version: 3.0.RC2 (As far as I can tell it has been present in all 3.X versions but NOT in 2.2.X)
Spring version: 3.0.4.RELEASE
JSF version: 2.0.4
Webflow version: 2.2.1.RELEASE
EDIT: Server is for example tomcat 7.0.12, but I have tried with others also without success.

flow xml:
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/webflow
        http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">

   <view-state id="start" view="sandbox.xhtml">
      <on-entry>
         <evaluate expression="new org.mypackage.SandboxBean()" result="flowScope.sandboxBean"/>
      </on-entry>
   </view-state>
</flow>


xhtml code:
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:p="http://primefaces.org/ui"
   xmlns:c="http://java.sun.com/jsp/jstl/core"
   xmlns:ap="http://java.sun.com/jsf/composite/ap"
   xmlns:dyn="http://java.sun.com/jsf/composite/dyn">

   <h:head>
      <ui:insert name="headIncludes" />
      <link type="text/css" rel="stylesheet" href="../styles/ap-base.css" />
   </h:head>

   <h:body>
      <h:form id="mainForm">
         <p:commandLink value="Show table" actionListener="#{sandboxBean.setShowTable(true)}" update=":mainForm" />
         <p:dataTable rendered="#{sandboxBean.showTable}" var="rowVar" value="#{sandboxBean.firstList}">
            <p:column filterBy="#{rowVar}" filterMatchMode="contains">
               <h:outputText value="#{rowVar}" />
            </p:column>
         </p:dataTable>
      </h:form>
   </h:body>
</html>


Bean code:
package org.mypackage;

import java.io.Serializable;
import java.util.ArrayList;

public class SandboxBean implements Serializable {
   private ArrayList<String> firstList;
   private boolean showTable;

   public SandboxBean() {
      firstList = new ArrayList<String>();
      firstList.add("TestString");
   }

   public ArrayList<String> getFirstList() {
      return firstList;
   }

   public boolean isShowTable() {
      return showTable;
   }

   public void setShowTable(boolean showTable) {
      this.showTable = showTable;
   }
}


Basically, the filtering is not doing anything at all. If you remove the 'rendered' attribute it works, and also if you reload the page when the table is already shown it works.

From, debugging, I've reached the conclusion that something is happening in the DataTable class in this section:
    public boolean isFilteringEnabled() {
        Object value = getStateHelper().get("filtering");

        return value == null ? false : true;
   }
   public void enableFiltering() {
      getStateHelper().put("filtering", true);
   }

If we put breakpoints here, we can see that when we load the table with ajax, enableFiltering is called and the subsequent isFilteringEnabled calls return true as expected. However, in the next request that is sent from the 'onkeyup' filtering event, isFilteringEnabled returns false as it can't find any 'filtering' property in the state helper. In the case where the table is rendered with the intial page request, the filtering request correctly returns true and the table is filtered. The likely conclusion from this is that the problem is in the webflow persistence, but I'm puzzled by the fact that it was working fine in 2.2.1.

If you need any additional information about our configuration don't hesitate to ask.
Primefaces 3.4.1-jQueryfix
Spring webflow 2.3.1
Mojarra jsf 2.1.7


Posts: 5985
I stopped using rendered="..." property of components, because I didn't like the resulting conditional/unexpected behavior. Since you have success when the dataTable "is rendered" on the page, can you add a style="#{bean.renderDataTable}" which will hide the rendering of the dataTable when necessary?

public String getRenderDataTable() {
    String renderDataTable = new String();
    if (render dataTable condition is met)
        renderDataTable = "display: inline|...";
    else
        renderDataTable = "display: none";
    return renderDataTable;
}


By the way, I didn't see you reference a scope in your bean. rendered property is mentioned in the quote/blog below.

Quote from one of BalusC's blogs: Managed bean scopes
@ViewScoped: a bean in this scope lives as long as you're interacting with the same JSF view in the browser window/tab. It get created upon a HTTP request and get destroyed once you postback to a different view. It doesn't immediately get destroyed when you leave/close the view by a GET Request, but it is not accessible the usual way anymore. JSF stores the bean in the UIViewRoot#getViewMap() with the managed bean name as key, which is in turn stored in the session. You need to return null or void from action (listener) methods to keep the bean alive. Use this scope for more complex forms which use ajax, data tables and/or several rendered/disabled attributes whose state needs to be retained in the subsequent requests within the same browser window/tab (view).
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.6, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache


Posts: 102
smithh032772 wrote:
I stopped using rendered="..." property of components, because I didn't like the resulting conditional/unexpected behavior. Since you have success when the dataTable "is rendered" on the page, can you add a style="#{bean.renderDataTable}" which will hide the rendering of the dataTable when necessary?

By the way, I didn't see you reference a scope in your bean. rendered property is mentioned in the quote/blog below.

I did consider using display:none instead, but as the tables can take 5-10 seconds to load it would be inconvenient to load that many of them at once. In that case it would be better to stop using ajax to load the tables and just have the entire page refresh.

The bean is located in the Flow Scope as you can see in the top code example. I believe this scope is webflow specific and not used in pure jsf.
Primefaces 3.4.1-jQueryfix
Spring webflow 2.3.1
Mojarra jsf 2.1.7


Posts: 5985
MTornros wrote:
I did consider using display:none instead, but as the tables can take 5-10 seconds to load it would be inconvenient to load that many of them at once. In that case it would be better to stop using ajax to load the tables and just have the entire page refresh.


1. To resolve the performance issue (5-10 seconds to load), have you tried LazyDataModel yet? Click here for some code that I provided.

2. So what did you decide to do? Are you just going with the full-page refresh instead of AJAX or PPR (Partial page refresh)?
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.6, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache


Posts: 102
1. We have considered LazyDataModel which could be useful with or without filtering (10 seconds is pretty bad even if it's just one table), but the backend does not expose a good way to select rows with an offset. Still, thanks for the code example, might be able to turn it into something.

2. We haven't decided on a final solution. The next release deadline is several months away so I'm now working on some other stuff while trying to get input here. The issue isn't blocking as filtering is merely a convenience feature, and 95%+ of the time the user will get the relevant table loaded when he first enters (in that case the filtering works fine).
Primefaces 3.4.1-jQueryfix
Spring webflow 2.3.1
Mojarra jsf 2.1.7


Posts: 5985
MTornros wrote:
1. We have considered LazyDataModel which could be useful with or without filtering (10 seconds is pretty bad even if it's just one table), but the backend does not expose a good way to select rows with an offset. Still, thanks for the code example, might be able to turn it into something.


I think there is a way to select rows with an offset. Please click here, and see how this PrimeFaces developer was selecting 1st row onPage event (p:dataTable event="page"). it's not the final post in that conversation, but below is the code excerpt from the URL I just provided above; bean and xhtml is provided/discussed too in that post.

3.04M DataTable's [page event] ignores process/update values
    ...
    public void onPage(PageEvent event) {
        if(!isServiceTypeSelected())
            return;   //no row was previously selected, so don't select first row in new page

        DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("mainForm:serviceTypes");
        selectedServiceType = (TServiceType) ((CommonLazyDataModel) dataTable.getValue()).getDataList().get(dataTable.getFirst());
        dataTable.setSelection(selectedServiceType);
    }
    ...


Also, see BalusC's blog, Using datatables. There is some useful code in this blog related to server-side and client-side. it's definitely a good read or reference.
Howard

PrimeFaces 5.1, Extensions 3.0.0, Push (Atmosphere 2.2.3)
TomEE+ 1.7.1 (Tomcat 7.0.55), MyFaces Core 2.2.6, JDK8
JUEL 2.2.7 | OmniFaces | EclipseLink-JPA/Derby | Chrome

Java EE 6 Tutorial|NetBeans|Google|Stackoverflow|PrimeFaces|Apache


Posts: 102
I ended up just changing the ajax event from 'update=":tableForm"' to 'oncomplete="window.location.reload()"'. Kind of an ugly solution, might try to implement a completely new table handler with lazy filtering, sorting and paging for a later release, but ended up being just too much work for this one.
Primefaces 3.4.1-jQueryfix
Spring webflow 2.3.1
Mojarra jsf 2.1.7


Return to General