Columns

Table of Contents

How to Use the ICEfaces Columns Component

The columns component provides a dynamic model for adding and deleting columns at run time.

The columns component can be used as a replacement for the standard h:column child of a standard dataTable. The following screenshot is of the ice:columns component demo in the component-showcase. Notice the ability to increase or decrease the number of columns displayed.

To use the full potential of the columns component, a DataModel for the rows and columns should be specified in a backing bean. Through the DataModels, the developer can specify the information that will be present in the table.





Creating a Basic Columns table


The creation of a basic columns component with custom non-changing data is a simple 3 step process.

  1. Create a String list for rows and columns
  2. Wrap each list in a DataModel
  3. Bind the DataModels to the page level dataTable and columns tags

In this example the page contains a numbered list of repeating Odd and Even values.

backing
private String[] index = {"1.", "2.", "3.", "4."};
private String[] heading = {"Odd", "Even"};
private DataModel rowModel = new ArrayDataModel(index);
private DataModel columnsModel = new ArrayDataModel(heading);

Once the back end objects have been created, they must be bound to the page level dataTable and columns tags. This is done through the value attribute of the components, as shown below:

<ice:dataTable value="#{backing.rowModel}" var="row">
    <ice:column>
        <ice:outputText value="#{row}"/>
    </ice:column>
    <ice:columns value="#{backing.columnsModel}" var="col">
        <ice:outputText value="#{col}"/>
    </ice:columns>
</ice:dataTable>

The row DataModel is assigned to the parent dataTable, and the columns DataModel as a value of the ice:columns component. By using a var declaration, we can output the current value of the DataModel as the component is iterated through during the rendering process.

The example page uses the above data for the rows and columns, as well as some minor styling. When viewed, it appears similar to:

The DataModels used in the backing bean are simple to create, and the next tutorial will demonstrate calculating page level information from the status of the back end objects.


Creating a Cross Columns table


This example will create another columns component, but without the use of static data. Instead the each row will be filled with color coded true / false values for each web browser. The finished product will look similar to:

The page level changes are minimal, the main addition is of the color coded value instead of a plain row / column output. This is achieved through a situational outputText, as shown below:

<ice:outputText value="#{backing.supportInfo}" style="color:#{backing.supportInfo eq 'true'?'green':'red'};"/>

We apply either a red or green CSS font color depending on the status of the supportInfo variable in the backing bean. When we look at the backing bean for this example, the power of linking the columns component to a DataModel becomes apparent. The getSupportInfo method is the main change since the last example, and contains code similar to the following:

backing
public Object getSupportInfo(){
    DataModel rowDataModel = getRowModel();
    if (rowDataModel.isRowAvailable())
    {
      Object event = getRowModel().getRowData();
      DataModel columnsDataModel = getColumnsModel();
      if (columnsDataModel.isRowAvailable())
      {
        Object browser = columnsDataModel.getRowData();
        return eventSupport.get(event+browser.toString());
      }
    }
    return null;
}

The above method will use the current row and column DataModel to retrieve the support information for that index. Basically we get the current row, ensure it is available (which means the page has loaded it, the component is rendered, etc.), and then do the same for the column. With the combined row / column data, we can check the support info string and return a proper result to the page.

So far the examples use static data that does not change once generated. The next tutorial will detail how columns data can be updated from the back end.


Creating an Updating Columns table


Similar to the previous examples, an updating columns component uses the same initial approach to the setup of pages and beans. The only difference is we will add a commandButton that will cause variables in the backing bean to change. This is reflected on the page as:

<ice:commandButton value="Update" actionListener="#{backing.next}"/>

Then the method called from this page level commandButton will need to be added to the backing bean. The goal of the button is to force the data in the columns component to update, and so the next() method will simply increase an integer (which will later be added to the page so the changes can be seen).

backing
public void next(ActionEvent event) {
    startFrom += 1+randomizer.nextInt(4);
}

As you can see the created method is very simple, basically adding a small random number to the startFrom integer. To allow the user to see the changes when they press the 'Update' button, the startFrom value will be displayed inside a columns component in the page, as shown below:

<ice:columns value="#{backing.columnsModel}" var="headings">
    <f:facet name="header">
        <h:outputText value="#{headings}" />
    </f:facet>
    <ice:outputText value="#{backing.startFrom}"/>
</ice:columns>

The end result is that when the user presses the 'Update' button, the next() method is called, which updates an integer. The changed value is automatically displayed as the contents of a columns component. Using this basic understanding, it's possible for a developer to update statistics from a real time persistence layer, etc.

When the above elements have been added, a page similar to the following is created:

As was shown, updating the data contents of a columns component was simple. But a developer may also wish to modify the attributes of the columns on the fly, which will be demonstrated in the next example.


Creating a Dynamic Columns table


Due to the coupling of a flexible DataModel and a powerful front end columns component, a developer has the option to dynamically modify not only the contents of the table, but also the attributes of the component. To demonstrate this, we will look in detail at allowing the user to increase or decrease the number of columns present on the page.

The first step is to add a friendly message and input field for the new number of columns. Alternatively a select input component or similar element could be used on the page. In addition, standard JSF validators could be attached to the input, as compared to the rudimentary method of performing back end level checks. An example of the user prompt and input field used is given below:

<ice:outputText value="Enter the number of columns to display (between 1 to 8)"/>
<ice:inputText value="#{backing.numberOfColumns}" valueChangeListener="#{backing.change}"/>

Next we will need to fill in the change() method that will be called when the value inside the inputText component is changed. The overall purpose of this method is to ensure a valid number of columns was entered, and if present then update the existing columns component to reflect the new count. This update will be done through modifying the back end DataModel, which will be shown in detail later. For now, an example of what the change() method would look like follows:

backing
public void change(ValueChangeEvent event) {
    int columnValue = (event.getNewValue() != null ?
        Integer.parseInt(event.getNewValue().toString()) : 7);

    if ((columnValue >= 1) && (columnValue <= 8)) {
        numberOfColumns = columnValue;
        updateModel();
    }
}

The bean handles validation instead of the page (again, this is just for simplicity). If the new number of columns is valid, we store it in the session bean and update the DataModel, through the updateModel() method. The contents of this method would be similar to the following:

backing
public void updateModel() {
    String[] array = new String[numberOfColumns];
    for (int i = 0; i < numberOfColumns; i++) {
        array[i] = String.valueOf(i+1);
    }
    columnsModel = new ArrayDataModel(array);
}

Basically, we take the newly updated numberOfColumns variable and recreate the columns DataModel, with numbers inserted for each line of header text.

When the above steps have been implemented, an application similar in appearance to the following would be produced:

You may have noticed a nice benefit of using the columns component this way - the back end is all that needs to be modified, the page level component itself hasn't changed much beyond the first example. This makes the many available changes to the DataModel a useful option to avoid having to update several pages.


Tutorial Source Code Downloads


Example Source Notes
columns-basic columns-basic source code Simple example of how to setup a basic hard coded columns component.
columns-cross columns-cross source code Example showing how to insert custom on the fly data into a columns component.
columns-dynamic columns-dynamic source code Demonstration of how the size and number of columns can be dynamic modified.
columns-update columns-update source code This example shows how the data inside a columns component can be updated to reflect user initiated changes.
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

© Copyright 2021 ICEsoft Technologies Canada Corp.