一覧のページネーション(ページ切り替え)
一覧画面は、スクロールで次の件数を読み足す方式(無限スクロール)です。これを「前へ・次へ・ページ番号」で切り替える方式に変える場合の設計メモです。本体の標準機能ではありません。
現行の仕組み(1.5.8.1)は 内部で動く SQL 文 > 画面側の追加読み込み にまとめています。改修に関係する点だけ挙げます。
- 1 回に読む件数はサイト設定の
GridPageSize(テーブルの管理 > 一覧の「ページ当たりの表示件数」、既定 20、10〜200)で、設定画面はすでにある。ページネーション後は「1 ページの件数」としてそのまま使える GridDataはすでにoffset・pageSizeを受け取り、全件数(TotalCount)も数えている。SQL(OFFSET ... FETCH NEXT、MySQL はLIMIT ... OFFSET)は変えなくてよい- 変える中心は、応答の
Append(末尾に足す)を「入れ替え」にすることと、スクロール検知をやめてページ切り替えの UI を足すこと
改修の方針
┌──────────────────────────────────────────┐
│ 一覧(1 ページ分) │
└──────────────────────────────────────────┘
◀ 前へ [1] [2] [3] … [10] 次へ ▶ 全 200 件(20 件/ページ)ページ番号 page から offset = (page - 1) × GridPageSize を作って、今と同じ GridOffset で GridRows に送ります。サーバー側は GridOffset の受け取り方を変えなくて済みます。
改修箇所
フロントエンド
ファイルは Implem.PleasanterFrontend/wwwroot/src/scripts/generals/ 配下です。
| ファイル | 改修内容 |
|---|---|
| scroll.js | $p.paging()・$p.dashboardPaging() のスクロール判定をやめる |
| observer.js | $p.pageObserve() の IntersectionObserver をやめる |
| grid.js | $p.setGrid() から $p.pageObserve('Grid') を外す。ダッシュボードの scroll resize も同様 |
| scrollevents.js、responsive.js | ダッシュボードとレスポンシブ表示のスクロール読み込みをやめる |
| _dispatch.js | Paging 応答の処理を、ページ切り替え UI の更新に変える |
新規 pagination.js | ページ番号・前へ・次へのクリックで #GridOffset を設定して $p.send() する |
| 新規のスタイル | 現在のページの強調、押せないボタンの表示 |
$p.gridPagination = function (page, suffix) {
suffix = suffix || '';
var pageSize = parseInt($('#GridPageSize' + suffix).val());
var $offset = $('#GridOffset' + suffix);
$offset.val((page - 1) * pageSize);
$p.setData($offset);
$p.send($('#Grid' + suffix));
};#GridPageSize は現行の一覧画面には無いので、ページ切り替えの HTML と一緒に出す必要があります。
サーバー側
| 対象 | 改修内容 |
|---|---|
各モデルの GridRows()(Issues・Results・Sites・Users・Groups・Depts・SysLogs・Registrations・Dashboards など) | Remove(".grid tr", _using: offset == 0) と Append("#Grid", …) を、ページ単位の入れ替え(ReplaceAll や Html)にする。Paging("#Grid") をやめ、ページ切り替えの HTML を返す |
| 同上 | Val("#GridOffset", …) は残し、現在のページと総ページ数も返す |
ResponseCollection | ページ切り替えの更新用のメソッドを足すか、既存の Html() で領域を入れ替える |
SiteSettings.GridNextOffset() | 任意のページへ飛ぶので「次の値」ではなく、ページから計算した値を使う |
HtmlGrids.cs または各モデルの Grid() | 一覧の下にページ切り替えの領域(例: <div id="GridPagination">)を出す。初回は 1 ページ目、総ページ数は ceil(TotalCount / GridPageSize) |
DashboardUtilities | ダッシュボードの一覧パーツにもサフィックス付き(#GridPagination_{サフィックス})で同じものを出す |
PublishesController.GridRows | 公開テーブルの一覧も同じ改修が要る |
1.5.8.1 の IssueUtilities.GridRows() の応答は IssueUtilities.cs です。GridRows アクションは ItemsController のほか、UsersController・GroupsController・DeptsController・SysLogsController・RegistrationsController・PublishesController・BackgroundJobsController・McpLogsController にもあります。
CodeDefiner の生成対象
Models/ 配下の *Utilities.cs や ItemModel.cs は CodeDefiner のテンプレートから生成されるコードを含みます。生成コードだけを直すと再生成で消えるので、テンプレート側も直してください。
ソート・フィルタとの関係
ソートやフィルタを変えたら 1 ページ目に戻します。現行でも GridOffset が 0(送られない場合も含む)のときは先頭から描き直すので、この動きはそのまま使えます。
ページ番号をどこで持つか
現行の一覧は、ソートやフィルタの状態をサーバーのセッション(Views.GetBySession())に持ち、URL には入れていません。GridRows へは /items/{siteId}/gridrows への POST で、GridOffset はフォームの値として送ります。ビューモードの切り替えなどではすでに history.pushState を使っていて、popstate のハンドラもあります。
方式 A: URL のクエリ(pushState で ?page=N)
図を読み込み中…
改修箇所は、ページ切り替え時の pushState、navigationevents.js の popstate でのページ復元、ItemsController.Index と ItemModel での初回表示時の ?page=N の読み取り、各モデルの初回表示を 0 以外の offset で作れるようにすることです。
方式 B: Ajax の POST だけ(URL は変えない)
#GridOffset を設定して $p.send() するだけで、URL・セッション・popstate には触りません。改修は最小ですが、ページの位置は共有・ブックマークできず、戻るボタンでは一覧から離れます。
方式 C: セッションに保存(View にページを持たせる)
View に GridPage を足してセッションに保存します。再読み込みや「一覧 → 編集 → 一覧」で同じページに戻れます。View.SetByForm・Views.GetBySession / SetSession・各モデルの IndexHtml() と GridRows() を直し、フィルタ変更時に GridPage を 1 に戻す処理が要ります。ビューの定義として保存する必要はないので、RecordingData の対象からは外します。
比較
| 観点 | A: URL | B: Ajax のみ | C: セッション |
|---|---|---|---|
| URL 共有・ブックマーク | ◎ | ✕ | ✕ |
| 戻る・進む | ◎ | ✕ | ✕ |
| 再読み込みでページを保つ | ◎ | ✕ | ◎ |
| 編集画面から戻ったとき | △(URL が変わると失われる) | ✕ | ◎ |
| 改修の規模 | 大 | 小 | 中 |
| ソート・フィルタとの整合 | △(URL とセッションの二重管理) | ◎ | ○ |
最小の改修なら B、画面から戻ったときにページを保ちたいなら C、URL の共有を重視するなら A です。A と C を組み合わせ、初回表示は ?page=N を優先し、無ければセッションから戻す方法もあります(改修は最大)。