Tabele o dynamicznej ilości kolumn w aplikacji JSF
W większości przypadków tabele mają z góry określoną liczbę, znaczenie i nazwy kolumn a zmienna jest liczba wierszy. Kolumny tabeli określają wtedy nijako typ obiektu a wiersze to poszczególne obiekty zgodne z tym typem. Nie wszystkie tabele mają jednak tą naturę. Czasem nieznana jest także liczba kolumn, np. w przypadku, gdy w tabeli chcemy pokazać stopę bezrobocia w wybranych krajach i wybranych okresach, latach albo miesiącach. Dziś pokażę, jak można zaimplementować taką tabelę w aplikacji JSF z użyciem komponentów dataTable i columns z biblioteki Tomahawk. Zacznijmy od końca, czyli jak będzie wyglądało to, co zbudujemy.
A teraz kod źródłowy strony. Zmienna o nazwie dataBean to ziarno zarządzane klasy DataBean, której kod pokaże później.
<t:dataTable var="period" value="#{dataBean.periodsList}">
<t:column>
<h:outputText value="#{period.name}" />
</t:column>
<t:columns value="#{dataBean.countriesList}" var="country">
<f:facet name="header">
<h:outputText value="#{country.name}" />
</f:facet>
<h:outputText value="#{dataBean.aggregateData.unemploymentRate} %" />
</t:columns>
</t:dataTable>
Kluczem do zrozumienia tego mechanizmu jest klasa javax.faces.model.DataModel. Wyrażenia dataBean.periodsList oraz dataBean.countriesList są właśnie tego typu, co widać w kodzie wspomnianej klasy DataBean. Poniżej jej kod źródłowy.
import java.util.ArrayList;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
public class DataBean {
private DataModel periodsList;
private DataModel countriesList;
public DataModel getPeriodsList() {
if (periodsList == null)
periodsList = new ListDataModel(fetchPeriodsList());
return periodsList;
}
public DataModel getCountriesList() {
if (countriesList == null)
countriesList = new ListDataModel(fetchCountriesList());
return countriesList;
}
public AggregateData getAggregateData() {
if (getPeriodsList().isRowAvailable() && getCountriesList().isRowAvailable()) {
return getData(
(Country) getCountriesList().getRowData(),
(Period) getPeriodsList().getRowData());
}
return null;
}
private ArrayList<Period> fetchPeriodsList() {
ArrayList<Period> periods = new ArrayList<Period>();
periods.add(new Period("Styczen 2007"));
periods.add(new Period("Luty 2007"));
periods.add(new Period("Marzec 2007"));
return periods;
}
private ArrayList<Country> fetchCountriesList() {
ArrayList<Country> countries = new ArrayList<Country>();
countries.add(new Country("Polska"));
countries.add(new Country("Litwa"));
countries.add(new Country("Rumunia"));
return countries;
}
private AggregateData getData(Country country, Period period) {
return new AggregateData(
country.getName().length() + period.getName().length());
}
}
Działa to więc tak, że dostarczamy kolekcje (typu javax.faces.model.DataModel) obiektów dla nagłówków poziomych i pionowych (metody getPeriodsList() i getCountriesList()) oraz implementujemy metodę (w tym wypadku jest to getAggregateData()), która dostarcza danych dla poszczególnych komórek "ciała" tabeli. Używając metody getRowData() klasy javax.faces.model.DataModel dowiadujemy się o obiektach będących w nagłówkach dla bieżącej komórki tabeli i na tej podstawie pobieramy odpowiednie dane. Zwróćmy uwagę, że pobranie danych oddelegowałem do metody getData(Country country, Period period). To jak pobieramy dane nie jest meritum tego artykułu, więc umieściłem tam kod-zaślepkę, ale w normalnym przypadku było by tu zapewne wywołanie jakiejś metody odpowiedniego serwisu logiki biznesowej, która z kolei pobierałaby dane z bazy danych. Dla kompletności podam jeszcze kod źródłowy klasy AggregateData. Analogicznie wyglądają klasy Country i Period. Są to ziarna JavaBeans z jednym atrybutem o nazwie name i konstruktorem.
public class AggregateData {
private int unemploymentRate;
public AggregateData(int unemploymentRate) {
this.unemploymentRate = unemploymentRate;
}
public int getUnemploymentRate() {
return unemploymentRate;
}
public void setUnemploymentRate(int unemploymentRate) {
this.unemploymentRate = unemploymentRate;
}
}
Brak komentarzy:
Prześlij komentarz