27 stycznia 2008

Tabele na stronach aplikacji JSF

W artykule "Tabele o dynamicznej ilości kolumn w aplikacji JSF" opisałem, w jaki sposób prezentować na stronach JSF tabele o nieustalonej ilości kolumn z użyciem komponentów dataTable i columns z biblioteki Tomahawk. Miał to być jeden z elementów większej układanki, której ostatecznym celem jest zbudowanie komponentu JSF – w formie kompozycji Facelets – adresującego problem, o którym pisałem z kolej w artykule "Prezentacja dużych tabel na stronach HTML". A problemem jest to, że – jak tam napisałem – "chciałbym mieć komponent, który umożliwi prezentację dużej tabeli na stronie HTML, przy czym tabela ta, jest zarówno bardzo długa, jak i bardzo szeroka". Dobrą wiadomością jest, że problem jest już niemalże rozwiązany, tzn. komponent ten powstał i działa niemalże tak jakbym sobie tego życzył, tyle że nie dało się go zaimplementować stosując podejście z użyciem wspomnianych komponentów Tomahawk. W sukurs przyszedł inny komponent, również z biblioteki Tomahawk, a mianowicie dataList. Dzisiaj napiszę więc o innym podejściu do implementacji tabel "o dynamicznej ilości kolumn w aplikacji JSF". Podejściu bazującym na komponencie dataList.

Zacznijmy od modelu danych. Żeby nie utrudniać, załóżmy że nagłówki – tj. nagłówek górny i boczny – oraz treść prezentowana w tabeli to będą zwykłe napisy, a więc nasz model danych może się opierać na obiektach klasy String. Poniżej interfejsy oraz przykładowe implementacje modelu danych potrzebnego dla naszej tabeli.

public interface TableDataModel {
public List<String> getColsHeaders();

public List<RowDataModel> getRowsDataModel();
}

public interface RowDataModel {
public String getRowHeader();

public List<String> getCellsList();
}

public class BasicTableDataModel implements TableDataModel {
private List<String> colsHeaders;

private List<RowDataModel> rowsDataModel;

public BasicTableDataModel(String[] colsHeaders) {
this.colsHeaders =
new ArrayList<String>(Arrays.asList(colsHeaders));
}

public List<String> getColsHeaders() {
return colsHeaders;
}

public List<RowDataModel> getRowsDataModel() {
if (rowsDataModel == null)
rowsDataModel = new ArrayList<RowDataModel>();

return rowsDataModel;
}

public void addRow(RowDataModel rowDataModel) {
getRowsDataModel().add(rowDataModel);
}
}

public class BasicRowDataModel implements RowDataModel {
private String rowName;

private List<String> cellsList;

public BasicRowDataModel(String rowName, String[] cellsArray) {
this.rowName = rowName;
this.cellsList =
new ArrayList<String>(Arrays.asList(cellsArray));
}

public List<String> getCellsList() {
return cellsList;
}

public String getRowHeader() {
return rowName;
}
}

Implementacje modelu danych pokazane powyżej zostały skonstruowane pod kątem łatwości użycia w kodzie przykładowym, więc ziarno zarządzane JSF, którego użyjemy do budowy strony jest niezwykle proste. Oto jego kod, w całości poświęcony inicjalizacji danych:

public class TableBackingBean {
private BasicTableDataModel dataModel;

public BasicTableDataModel getDataModel() {
if (dataModel == null) {
dataModel = new BasicTableDataModel(
new String[] { "Ford", "Opel", "BMW" });

dataModel.addRow(new BasicRowDataModel(
"2005", new String[] {"12", "8", "10" }));

dataModel.addRow(new BasicRowDataModel(
"2006", new String[] {"-6", "2", "12" }));

dataModel.addRow(new BasicRowDataModel(
"2007", new String[] {"16", "18", "-2" }));
}

return dataModel;
}
}

O komponencie dataList możemy myśleć, nieco upraszczając, jak o implementacji pętli "for each". Użyjemy go więc jako iteratora po elementach kolekcji modelu danych i w ten sposób zbudujemy tabelę HTML. Oto, jak wygląda nasza strona:

<table>
<tr>
<td> </td>
<t:dataList var="headerCell"
value="#{tableBackingBean.dataModel.colsHeaders}">

<td>#{headerCell}</td>
</t:dataList>
</tr>

<t:dataList var="bodyRow"
value="#{tableBackingBean.dataModel.rowsDataModel}">

<tr>
<td>#{bodyRow.rowHeader}</td>

<t:dataList var="cell" value="#{bodyRow.cellsList}">
<td>#{cell} %</td>
</t:dataList>
</tr>
</t:dataList>
</table>

Ziarno zarządzane o nazwie tableBackingBean to naturalnie instancja klasy TableBackingBean. Efektem końcowym jest tabela prezentująca procentowy wzrost, lub spadek, ilości sprzedawanych aut przez poszczególnych producentach w poszczególnych latach.

Brak komentarzy: