AjaxFallbackDefaultDataTableに関するメモ - その4
今回は表示する時にいろいろ手を加える際(例えば日付のフォーマット等)のやりかたメモ。
「Countryの各フィールドの値に対して「*」等を前後に付加する」みたいな処理をする場合は下記のようになります。
/**いろいろ省略**/ columnList.add(new PropertyColumn(new Model("ID"),"id","countryId"){ @Override public void populateItem(Item item, String componentId, IModel model) { Country c = (Country)model.getObject(); item.add(new Label(componentId,"* "+c.getCountryId()+" *")); } }); columnList.add(new PropertyColumn(new Model("Name"), "countryName"){ @Override public void populateItem(Item item, String componentId, IModel model) { Country c = (Country) model.getObject(); item.add(new Label(componentId, "- " + c.getCountryName() + " -")); } }); columnList.add(new PropertyColumn(new Model("Lang"), "lang"){ @Override public void populateItem(Item item, String componentId, IModel model) { Country c = (Country) model.getObject(); item.add(new Label(componentId, "+ " + c.getLang() + " +")); } });
1番最初のエントリーにて『列毎に表示する感じをうける』と書いたのはこのせいです。
ListView とかだと1行毎に処理をするって感じがして直感的だと思いますが、上記の場合はいちいち各カラム毎にpopulateItemをオーバーライドして Countryオブジェクトを取得して・・・といった面倒な処理が発生してしまいます。この点が個人的に不満なところです。可読性も良いとは言えませんしねぇ。
こういう場合はViewHelperを作成するのがいいんじゃないかと思います。
例えばこんなクラスを作成し
public class CountryViewHelper implements Serializable{ private Country country; public CountryViewHelper(Country country) { this.country = country; } public String getCountryId(){ return "* "+country.getCountryId()+" *"; } public String getCountryName(){ return "- "+country.getCountryName()+" -"; } public String getLang(){ return "+ " + country.getLang() + " +"; } }
次にCountryDataProviderをちょっと変更します。
private class CountryDataProvider extends SortableDataProvider { /*** 省略 ***/ @Override public IModel model(final Object object) { return new LoadableDetachableModel(){ @Override protected Object load() { //ここでViewHelperを返す。 return new CountryViewHelper((Country)object); } }; } }
こうするとPropertyColumnを生成する箇所はわざわざpopulateItemをオーバーライドすることなく下記のように前回までのシンプルなソースになります。
columnList.add(new PropertyColumn(new Model("ID"),"id","countryId")); columnList.add(new PropertyColumn(new Model("Name"), "countryName")); columnList.add(new PropertyColumn(new Model("Lang"), "lang"));
ViewHelper はJSPベースのフレームワークだとカスタムタグによって実現されることが多いと思いますが、Wicketの場合POJOとして作成でき、単体テストとかバリバリやれます。この点は自分がWicket大好きな理由の1つです。Viewの部分をJavaでリファクタリングしまくれるこの楽しさ!! ・・・なんか話の方向が変わっちゃったけど(゚ε゚)キニシナイ
しかし、実はLoadableDetachableModelのloadにてViewHelperオブジェクトを返すというやり方は1.3までなんですよねぇ〜(やろうと思えば1.4でもいけますが・・)。1.4からはGenerics対応になるので、上記にて厳密に型パラメータを定義する場合は下記のようになります。
private class CountryDataProvider extends SortableDataProvider<Country> { /*** 省略 ***/ @Override public IModel<Country> model(final Country country) { return new LoadableDetachableModel<Country>(){ @Override protected Country load() { //コンパイルエラー>< return new CountryViewHelper(country); } }; } }
LoadableDetachableModelにて型パラメーターを定義せずmodelメソッドに@SuppressWarnings("unchecked")を追加すればOKではあるんですがなんか美しくない・・・・。
他の方法としては、PropertyColumnのcreateLabelModelメソッドにてを拡張するのがいいのかなぁ。
下記のようなPropertyColumnのサブクラスを1つ作成しておくとか??
private class MyPropertyColumn extends PropertyColumn<Country>{ public MyPropertyColumn(IModel<String> displayModel, String propertyExpression) { super(displayModel, propertyExpression); } public MyPropertyColumn(IModel<String> displayModel, String sortProperty, String propertyExpression) { super(displayModel, sortProperty, propertyExpression); } @Override protected IModel<?> createLabelModel(final IModel<Country> rowModel) { IModel<CountryViewHelper> model = new LoadableDetachableModel<CountryViewHelper>() { @Override protected CountryViewHelperload() { return new CountryViewHelper(rowModel.getObject()); } }; return new PropertyModel<CountryViewHelper>(model,getPropertyExpression()); } }
一応こっちのほうがよさげですかねぇ。
ん??ということは1.3の場合もCountryDataProvider#modelメソッドを変更するのではなく上記MyPropertyColumnのようなクラスを作成したほうがいいということですかね??
う〜ん、なんか中途半端でゴメンナサイ・・・。
間違ってるところとか勘違いしている点がある場合、ご指摘しただけると嬉しいです。