Grid サンプル ページャー編
フロントエンド
昨日、掲載したソースに若干手を加える事でページャー機能が使えるようになります。さっそくソースを。
entity-paging-grid.html
<html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>ページャー グリッド</title> <link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="../ext/resources/css/xtheme-gray.css" /> <!-- GC --> <!-- LIBS --> <script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script> <!-- ENDLIBS --> <script type="text/javascript" src="../ext/ext-all.js"></script> <style type="text/css"> </style> <script type="text/javascript"> <!-- //<![CDATA[ fields = [ 'company', 'price', 'change', 'pctChange', {name:'lastChange', type:'date', dateFormat:'u'} ]; store = new Ext.data.Store({ proxy: new Ext.data.HttpProxy({ url: 'entityPagenation.json', method: 'GET' }), reader: new Ext.data.JsonReader({ root: 'root', totalProperty: 'totalProperty', fields: fields }) }); colModel = new Ext.grid.ColumnModel([ {header: "Company", width: 160, sortable: true, dataIndex: 'company'}, {header: "Price", width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'}, {header: "Change", width: 75, sortable: true, dataIndex: 'change'}, {header: "% Change", width: 75, sortable: true, dataIndex: 'pctChange'}, {header: "Last Updated", width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'} ]); bbar = new Ext.PagingToolbar({ pageSize: 20, store: store, displayInfo: true, displayMsg: 'Displaying topics {0} - {1} of {2}', emptyMsg: "No topics to display" }); grid = new Ext.grid.GridPanel({ title:'Array Grid', stripeRows: true, height:400, width:600, store: store, colModel: colModel, bbar: bbar }); Ext.onReady(function(){ grid.render('grid-example'); store.load({params:{start:0, limit:20}}); }); //]]> //--> </script> </head> <body> <div id="center"> <div id="grid-example"></div> </div> </body> </html>
前回のソースに比べて追加した箇所の解説。
まず Ext.data.Store の url はページャー機能対応サービスクラスの url に変更。サービスクラスに関しては後述する。reader には totalProperty 属性と root 属性が追加された。totalProperty は全件数が代入されていて root には従来の Grid データ内容が代入されている。これはサーバーサイドから返される JSON の値が全件数と Grid データの二つの値で返ってくる事に対しての対応である。コントロール・モデル部の追加は以上。
次にビュー側について。ページャー機能の為に新しく Ext.PagingToolbar のオブジェクトを生成。bbar とした。bbar を Grid 属性の bbar に設定する。これでページャー表示の為のツールバーが Grid に追加される。ページャー機能のオブジェクトはパラメーター start と limit の GET リクエストを行う。
最後に Ext.onReady の store.load({params:{start:0, limit:20}}); は最初に表示する Grid データの内容の範囲をサーバーサイドにパラメーターとして渡す仕組みになっている。つまり offset 0、limit 20 のレコード郡を取得するのである。先に上げた Ext.PagingToolbar と同じ挙動となっている。そのため、limit は bbar で指定した pageSize と同じ値にする事。
サーバーサイド
フロントエンドからはパラメーター start=0&limit=20 のような形で GET リクエストが送られてくる。これを受け取り、返す値を作成するメソッドを書く。
EntitySearchCondition.java
package sample.web.grid; public class EntitySearchCondition { public int start; public int limit; }
EntityPagenationService.java
package sample.web.grid; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; public class EntityPagenationService { public List<Entity> getList() { Entity entity = null; List<Entity> list = new ArrayList<Entity>(); for (int i = 0; i < 10000; i++) { entity = new Entity(); entity.company = "ほげ Co " + i; entity.price = 80.12f; entity.change = 0.42f; entity.pctChange = 1.47f; entity.lastChange = new Date(); list.add(entity); } return list; } public Map<String, Object> find(EntitySearchCondition condition) { List<Entity> src = getList(); Map<String, Object> m = new HashMap<String, Object>(); m.put("totalProperty", src.size()); m.put("root", src.subList(condition.start, condition.start + condition.limit)); return m; } }
start=0&limit=20 と送られてきたパラメーターは find() の引数 EntitySearchCondition condition に自動的にマッピングされ値が代入される。その情報を元にオブジェクト配列を作成。今回のクラスではオブジェクト配列は全件数作成し size() で全件数を取得。subList() で表示分のオブジェクト配列を作成し、それぞれ Mapオブジェクトに put した。put の際にフロントエンドの Ext.data.Store の reader で指定した属性名をキーにする事。作成された Mapオブジェクトはビュー側で全件数と Grid 内容の二つを扱う適切な形の JSON に変換されフロントエンドに返される。
以上でページャー機能の実装が完了。
ビューのオブジェクトがきちんと独立しており、必要な時に Grid の属性として渡すだけでページャー機能が容易に実現できるのがわかる。それに伴うモデル・コントロール部分も必要最小限の変更で対応可能。Ext.data.Store の proxy と reader がきちんと役割分担出来ている為であろう。
フロントエンドとサーバーサイドも非常にシンプルに書く事が出来るのが以上でわかってもらえたと思う。