まずは作ったファイル
pager.component.ts
@Component()
内のselector
, templateUrl
は適宜書き換えるべし。
pager.component.ts
import { Component, Input, EventEmitter, Output, OnChanges } from '@angular/core';
@Component({
selector: 'pager',
templateUrl: '/pager.component.html'
})
export class PagerComponent implements OnChanges
{
/** 現在のページ番号 */
@Input()
public currentPage: number;
/** 合計アイテム数 */
@Input()
public totalItemCount: number;
/** ページを切り替えた際の通知用 */
@Output()
public pageChanged = new EventEmitter<number>();
/** 1ページに何個のアイテムを表示するか(初期値: 15) */
@Input()
public perPage: number = 15;
/** ページャーの表示サイズ(初期値: 7) */
@Input()
public size: number = 7;
/** 総ページ数 */
public totalPages: number;
/** 表示すべきページ番号群 */
public displayPages: number[];
public constructor() {}
/**
* プロパティバインドした変数の変更を検知し
* totalPages、displayPagesを更新する
* @param changes
* @returns {void}
*/
public ngOnChanges(changes): void
{
if (changes.totalItemCount) {
this.totalPages = Math.ceil(changes.totalItemCount.currentValue / this.perPage);
this.updateDisplayPages();
}
}
/**
* ページ番号を直接指定して移動
* @param pageNumber
* @returns {void}
*/
public jump(pageNumber: number): void
{
this.currentPage = pageNumber;
this.updateDisplayPages();
}
/**
* 「次」ボタンを押して移動
* @returns {void}
*/
public next(): void
{
if (this.currentPage < this.totalPages) {
this.currentPage++;
this.updateDisplayPages();
}
}
/**
* 「前」ボタンを押して移動
* @returns {void}
*/
public prev(): void
{
if (this.currentPage > 1) {
this.currentPage--;
this.updateDisplayPages();
}
}
/**
* displayPagesを正しい状態に更新する
* @returns {void}
*/
private updateDisplayPages(): void
{
this.displayPages = this.calcDisplayPages();
// EventEmitterを通じて変更を通知
this.pageChanged.emit(this.currentPage);
}
/**
* sizeを考慮して表示するべきページ配列を返却する
* @returns {number[]}
*/
private calcDisplayPages(): number[]
{
if (this.size >= this.totalPages) {
return this.range(1, this.totalPages);
}
// 中間を求める(切り上げ)
let mid = Math.ceil(this.size / 2);
if (this.currentPage <= mid) {
return this.range(1, this.size);
}
// 現在のページを中心に前後を埋める
let zero = ((this.size - 1) % 2) === 0;
let before, after;
if (zero) {
before = (this.size - 1) / 2;
after = before;
} else {
before = Math.floor((this.size - 1) / 2);
after = before + 1;
}
if (this.totalPages - after < this.currentPage) {
return this.range(this.totalPages - this.size + 1, this.size);
}
let start = this.currentPage - before;
return this.range(start, this.size);
}
/**
* 開始値と長さを受け取り配列を生成する
* @param start
* @param length
* @returns {number[]}
*/
private range(start: number, length: number): number[]
{
let arr = [];
for (let i = start; i < start + length; i++) {
arr.push(i);
}
return arr;
}
}
pager.component.html
ul
、li
を用いたベーシックなpagerテンプレート。
現在位置のli
にはactive
クラスを付与、またa
をspan
に変更。
pager.component.html
<ul class="pagination">
<li><a href="javascript:;" (click)="prev()">«</a></li>
<li *ngFor="let page of displayPages" [ngClass]="{'active': page === currentPage}">
<a href="javascript:;" *ngIf="page !== currentPage" (click)="jump(page)">{{ page }}</a>
<span *ngIf="page === currentPage">{{ page }}</span>
</li>
<li><a href="javascript:;" (click)="next()">»</a></li>
</ul>
使い方
使う側のコンポーネントは例えばこんな感じ。
lists.component.ts
lists.component.ts
import { Component, OnInit } from '@angular/core';
import { PagerComponent } from './pager.component';
@Component({
selector: 'lists',
templateUrl: '/lists.component.html',
directives: [
PagerComponent
]
})
export class ListsComponent implements OnInit {
public page: number;
public totalItemCount: number;
public constructor() {}
public ngOnInit()
{
// 例えばapiよりデータを取得してきたとする
setTimeout(() => {
// ページ番号をセット
this.page = 1;
// 全アイテム件数をセット
this.totalItemCount = 123;
}, 1000);
}
public update(page: number)
{
// ページャーを操作した際の処理を記述
alert(`現在${page}ページです`);
}
}
lists.component.html
currentPage
、totalItemCount
は必須。perPage
、size
は任意。
pageChanged
にページ変更時に実行したい関数を渡す。$event
でページ番号を受け取れる。
lists.component.html
<pager
*ngIf="totalItemCount"
[currentPage]="page"
[totalItemCount]="totalItemCount"
[perPage]="10"
(pageChanged)="update($event)"></pager>