DataTable paginator issue: dynamic columns and inside repeat

UI Components for JSF
Post Reply
JorgeGonc
Posts: 2
Joined: 09 Jan 2012, 13:08

15 May 2012, 20:11

Hi there,

PROBLEM

We have a problem when using the DataTable component inside a repeater (ui:repeat or a4j:repeat).
If the DataTable columns are generated dynamically and we have something in the footer (like the paginator), then the footer will be rendered with an incorrect "colspan".

Has we have a DataTable inside a repeater, when rendering each instance, the "getColumnsCount" (DataTable.java) method only returns the correct value for the first instance. The 2nd, 3rd, 4th, 5th...etc instances get the same result of the first one.

For what i saw this could be a problem also when using "row expansion" and "facet" functionalities.

Here is a code sample that shows this problem.

Test.xhtml

Code: Select all

<ui:composition 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:a4j="http://richfaces.org/a4j">

		<ui:repeat id="irow" value="#{testBean.columnsByDT}" var="dtRow" varStatus="dtRowStatus">
			<p:dataTable id="table" 
						 value="#{testBean.data}" 
						 var="row"
						 paginator="true" paginatorAlwaysVisible="false" paginatorPosition="top" rows="10"
						 currentPageReportTemplate="{currentPage} of {totalPages}"
						 paginatorTemplate="#{i18n['table.pageLabel']} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}">
			
				<p:columns value="#{dtRow}" var="column" columnIndexVar="colIndex" sortBy="#{row.getColValue(column)}" filterBy="#{row.getColValue(column)}" filterMatchMode="contains">
					<f:facet name="header">#{column}</f:facet>
					<h:outputText value="#{row.getColValue(column)}" />
				</p:columns>
			</p:dataTable>
		</ui:repeat>
</ui:composition>
TestBean.java

Code: Select all

public class TestBean {
	private List<List<String>> columnsByDT; 
	private List<TestEntity> data;
	
	/**
	 * Default constructor.
	 */
	public TestBean() {
		// Initialize data tables
		setColumnsByDT(new ArrayList<List<String>>());
		
		//Data table 1 columns
		List<String> columns=new ArrayList<String>();
		columns.add("id");
		columns.add("name");
		columns.add("description");
		getColumnsByDT().add(columns);
		
		//Data table 2 columns
		columns=new ArrayList<String>();
		columns.add("id");
		columns.add("name");
		columns.add("description");
		columns.add("additional 1");
		getColumnsByDT().add(columns);
		
		//Data table 3 columns
		columns=new ArrayList<String>();
		columns.add("id");
		columns.add("name");
		columns.add("description");
		columns.add("additional 1");
		columns.add("additional 2");
		getColumnsByDT().add(columns);
		
		
		// initialize data
		setData(new ArrayList<TestEntity>());
		for(int i=0;i<100;i++){
			TestEntity ent = new TestEntity();
			ent.setId(i);
			ent.setName(UUID.randomUUID().toString());
			ent.setDescription("test");
			ent.setAdditional1("test add 1");
			ent.setAdditional2("test add 2");
			getData().add(ent);
		}
	}

	
	public List<List<String>> getColumnsByDT() {
		return columnsByDT;
	}
	public void setColumnsByDT(List<List<String>> columnsByDT) {
		this.columnsByDT = columnsByDT;
	}

	public List<TestEntity> getData() {
		return data;
	}
	public void setData(List<TestEntity> data) {
		this.data = data;
	}

	/* Test Object class */
	public class TestEntity{
		private int id;
		private String name;
		private String description;
		private String additional1;
		private String additional2;
		
		public int getId() {
			return id;
		}
		public void setId(int id) {
			this.id = id;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getDescription() {
			return description;
		}
		public void setDescription(String description) {
			this.description = description;
		}
		public String getAdditional1() {
			return additional1;
		}
		public void setAdditional1(String additional1) {
			this.additional1 = additional1;
		}
		public String getAdditional2() {
			return additional2;
		}
		public void setAdditional2(String additional2) {
			this.additional2 = additional2;
		}
		
		public Object getColValue(String colName){
			if(colName.equals("id")){
				return getId();
			}else if(colName.equals("name")){
				return getName();
			}else if(colName.equals("description")){
				return getDescription();
			}else if(colName.equals("additional1")){
				return getAdditional1();
			}else if(colName.equals("additional2")){
				return getAdditional2();
			}
			else{
				return "invalid column name";
			}
		}
	}
}
Temporary Solution

We don't like to use this kind of "hack" has we prefer to keep the framework has it is (like all of you for sure). But this time we had to do it.
Here is the temporary "hack" that we applied.

Basically, we reset the "columnsCount" to "-1" to force recalculation whenever the component clientId changes (afaik, inside a repeater there is only one component representing all instances and each instance specific "data" is kept as "state").
So for what i understand, when changing the component state to a specific instance, Primefaces should reset this variable or store it has state.
If i'm wrong just tell me, i would like to know more about how components behaves inside repeaters.

org.primefaces.component.datatable.DataTable.java (Method: getColumnsCount() )

Code: Select all

   private int columnsCount = -1;
   //Hack
   private String columnsCountDTClientId = ""; 

   public int getColumnsCount() {
    	 //Hack
        if(!columnsCountDTClientId.equals(getClientId())){
        	columnsCount=-1;
        	columnsCountDTClientId=getClientId();
        }
        //Hack End
        ...

   }
I've also created an issue: http://code.google.com/p/primefaces/iss ... il?id=4038


Thks in advance.

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 53 guests