how to get primefaces datatable columns order and width from ManagedBean

Jalal Sordo picture Jalal Sordo · Feb 3, 2014 · Viewed 12.7k times · Source

i'm using primefaces 4.0, JSF Mojarra 2.2.2 and here is my datatable code :

<p:dataTable id="tabexam"
             paginatorPosition="bottom"
             var="exam"
             value="#{dyna.examViewDataModel}"
             widgetVar="examTable"
             emptyMessage="aucun résultat trouvé pour votre recherche"
             paginator="true"
             rows="40" 
             selection="#{dyna.selectedExamen}"
             filteredValue="#{dyna.filteredexams}"
             selectionMode="single"
             resizableColumns="true"  
             draggableColumns="true"
             paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"  
             rowsPerPageTemplate="40,80,120">

<p:columns value="#{datatableBean.table}"
           var="column"
           headerText="#{column.userListname}"
           rendered="#{column.visible}"
           resizable="#{column.resizable}"
           width="#{column.width}"
           columnIndexVar="colIndex">

   <h:panelGroup>
             <p:outputLabel value="#{column.dbname}" styleClass="fonty"/>
   </h:panelGroup>

 </p:columns>

</p:dataTable>

Here what I've tried so far, but I get empty Strings for getHeaderText in the console and empty width too, i wonder what i'm missing

UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
    DataTable tabler = (DataTable) view.findComponent(":form1:tabexam");
    List<UIColumn> coler = tabler.getColumns();

    for (int i = 0; i < coler.size(); i++) {

        System.out.println("/////////////////");
        System.out.println(coler.get(i).getValueExpression("headerText").getValue(FacesContext.getCurrentInstance().getELContext()));
        System.out.println(coler.get(i).getHeaderText());
        System.out.println(coler.get(i).isRendered());
        System.out.println(coler.get(i).isResizable());
        System.out.println(coler.get(i).getWidth());
        System.out.println("/////////////////");

    }
 System.out.println(coler.size());

Note that coler.size() gives the number of columns shown on the datatable. but the coler.get(i).getHeaderText() always gives empty String.

Answer

Michele Mariotti picture Michele Mariotti · Feb 3, 2014

you are mistaking something:

  1. do not nest p:column inside p:columns
  2. DataTable.getColumns does not return what you expect:

    public List<UIColumn> getColumns() {
        if(columns == null) {
            columns = new ArrayList<UIColumn>();
            FacesContext context = getFacesContext();
            char separator = UINamingContainer.getSeparatorChar(context);
    
            for(UIComponent child : this.getChildren()) {
                if(child instanceof Column) {
                    columns.add((UIColumn) child);
                }
                else if(child instanceof Columns) {
                    Columns uiColumns = (Columns) child;
                    String uiColumnsClientId = uiColumns.getClientId(context);
    
                    for(int i=0; i < uiColumns.getRowCount(); i++) {
                        DynamicColumn dynaColumn = new DynamicColumn(i, uiColumns);
                        dynaColumn.setColumnKey(uiColumnsClientId + separator + i);
                        columns.add(dynaColumn);
                    }
                }
            }
        }
    
        return columns;
    }
    

this returns a synthetic emulation: only columnKey per column, and, as you stated, the correct number of columns.

generally speaking, p:columns is ONE component and when you access it from controller layer, you have to refer to its DECLARATION (single component) instead of its REPRESENTATION (multiple columns)

  1. since you are backing p:columns with your #{datatableBean.table} you should already have all the information you are trying to get from DataTable component, in a reverse-engineered fashion.

update

oh, now i realize what you want to do. you have to use event listeners for that.

from PF showcase:

<p:dataTable var="car" value="#{tableBean.carsSmall}" widgetVar="cars" draggableRows="true">  

    <p:ajax event="colReorder" listener="#{tableBean.onColReorder}" update=":some:component" />  

    <p:ajax event="colResize" listener="#{tableBean.onColResize}" update=":some:component"/>    

    <!-- columns here -->  
</p:dataTable> 

listening for these events in backing bean and mantain these informations should solve your problem

update 2

whew, it was not simple at all.

due to Primefaces bug for dynamic column resizing (at least for my tries) and incomplete column reordering event implementation, this is what came out:

<h:form id="form">
    <h:panelGroup id="model">
        <ui:repeat var="column2" value="#{testBean.columnList2}">
            <div>#{column2.title} - #{column2.width}</div>
        </ui:repeat>
    </h:panelGroup>

    <p:dataTable var="elem" value="#{testBean.elementList}" resizableColumns="true" draggableColumns="true">
        <p:ajax event="colReorder" listener="#{testBean.onColumnReorder}" update=":form:model" />  
        <p:ajax event="colResize" listener="#{testBean.onColumnResize}" update=":form:model"/>  

        <c:forEach var="column" items="#{testBean.columnList}">
            <p:column headerText="#{column.title}" rendered="#{column.visible}" width="#{column.width}">
                <f:attribute name="myCol" value="#{column}"/>
                <span>#{elem[column.property]}</span>
            </p:column>
        </c:forEach>
    </p:dataTable>
</h:form>

and this bean:

@ManagedBean
@ViewScoped
public class TestBean implements Serializable
{
    private static final long serialVersionUID = 1L;

    private List<MyColumn> columnList;
    private List<MyColumn> columnList2;
    private List<MyElement> elementList;

    public class MyColumn
    {
        private String title;
        private String property;
        private boolean visible = true;
        private boolean resizable = true;
        private int width = 100;

        public MyColumn(String title, String property, boolean visible, boolean resizable, int width)
        {
            super();
            this.title = title;
            this.property = property;
            this.visible = visible;
            this.resizable = resizable;
            this.width = width;
        }

        // getters and setters
    }

    public class MyElement
    {
        private String code;
        private String name;
        private String type;

        public MyElement(String code, String name, String type)
        {
            super();
            this.code = code;
            this.name = name;
            this.type = type;
        }

        // getters and setters
    }

    @PostConstruct
    public void init()
    {
        columnList = new ArrayList<>();
        columnList.add(new MyColumn("element code", "code", true, true, 100));
        columnList.add(new MyColumn("element name", "name", true, true, 100));
        columnList.add(new MyColumn("element type", "type", true, true, 100));

        columnList2 = new ArrayList<>(columnList);

        elementList = new ArrayList<>();
        elementList.add(new MyElement("001", "foo", "normal"));
        elementList.add(new MyElement("002", "bar", "strange"));
        elementList.add(new MyElement("003", "xyz", "normal"));
        elementList.add(new MyElement("004", "abc", "nothing"));
    }

    public void onColumnResize(ColumnResizeEvent event)
    {
        UIColumn column = event.getColumn();
        int width = event.getWidth();

        UIComponent colComponent = (UIComponent) column;
        MyColumn myCol = (MyColumn) colComponent.getAttributes().get("myCol");

        myCol.setWidth(width);
    }

    public void onColumnReorder(AjaxBehaviorEvent event)
    {
        DataTable table = (DataTable) event.getSource();

        columnList2.clear();

        for(UIColumn column : table.getColumns())
        {
            UIComponent colComponent = (UIComponent) column;

            MyColumn myCol = (MyColumn) colComponent.getAttributes().get("myCol");
            columnList2.add(myCol);
        }
    }

    // getters and setters

}

updated code, you can find ordered columns in columnList2. now are also shown in the form. now you can use columnList2 to store oreder and widths to db.