How to Use the ICEfaces Columns ComponentThe 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.
The rest of this tutorial will cover the following topics: Creating a Basic Columns table
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
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
<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
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
|
Columns
© Copyright 2021 ICEsoft Technologies Canada Corp.