web-dev-qa-db-ja.com

Angular 4でページ区切りコンポーネントを作成するにはどうすればよいですか?

私は/list/students?page=5&rows=10のようなAPIエンドポイントにページネーションパラメータpagesizeを指定しています。 angular2ページネーションコンポーネントを作成したいのですが。

入力パラメータは

  • ページ
  • サイズ

また、矢印ボタンで特定のページやサイズに移動したい。

このコンポーネントを実装するにはどうすればよいですか?

5
U Gold

以下のコードとサービスを使用してページングコンポーネントを作成できます

app.component.html

<paging-component
  [TotalItems]="pagination.TotalItems"
  [CurrentPage]="pagination.CurrentPage"
  [PageSize]="pagination.PageSize"
  [TotalPageLinkButtons]="pagination.TotalPageLinkButtons"
  [RowsPerPageOptions]="pagination.RowsPerPageOptions"
  (onPageChange)="myChanges($event)"></paging-component>

app.component.tsは以下のとおりです。

import {Component} from '@angular/core';

@Component({
  selector   : 'app-root',
  templateUrl: './app.component.html',
  styleUrls  : ['./app.component.css']
})
export class AppComponent {

  pagination = {
    TotalItems: 100,
    CurrentPage: 1,
    PageSize: 10,
    TotalPageLinkButtons: 5,
    RowsPerPageOptions: [10, 20, 30, 50, 100]
  };

  /* Paging Component metod */
  myChanges(event) {
    this.pagination.CurrentPage = event.currentPage;
    this.pagination.TotalItems = event.totalItems;
    this.pagination.PageSize = event.pageSize;
    this.pagination.TotalPageLinkButtons = event.totalPageLinkButtons;
  }
}

app.component.module

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';

import {AppComponent} from './app.component';
import {PagingComponent} from './components/paging-component/paging-component.component';
import {PagingService} from './service/paging-service.service';

@NgModule({
  declarations: [
    AppComponent,
    PagingComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [ PagingService],
  bootstrap: [AppComponent]
})
export class AppModule { }

paging-service.service.tsは

import { Injectable } from '@angular/core';

@Injectable()
export class PagingService {


  /**
   * @param totalItems : Total items to be listed
   * @param currentPage : Current page number ( Pages starting from 1 not 0)
   * @param pageSize : The number of items in the page
   * @param totalPageLinkButtons : The number of total page link buttons
   * @returns {{
   * startPage: number,
   * endPage: number,
   * startIndex: number,
   * endIndex: number,
   * totalPageLinkButtons: number,
   * totalItems: number,
   * currentPage: number,
   * pageSize: number,
   * totalPages: number,
   * pages: (Observable<number>|any)
   * }}
   */
  getPagingServiceItems(totalItems: number, currentPage: number = 1, pageSize: number = 10, totalPageLinkButtons: number = 5) {

    totalItems = totalItems || 1;

    /* if currentPage not exists default value will be '1' */
    currentPage = currentPage || 1;

    /* The default value of the number of items in the page is 10 if not exist */
    pageSize = pageSize || 10;

    /* The default value of the number of total page link buttons is 10 if not exist */
    totalPageLinkButtons = totalPageLinkButtons || 10;

    /* calculate total pages  */
    const totalPages = Math.ceil(totalItems / pageSize);


    let startPage: number; // start Page Button number
    let endPage: number;   // end Page Button number

    if (totalPages <= totalPageLinkButtons) {

      // less than totalPageButtons then show all
      // 1,2,3,.., totalPages are buttons
      startPage = 1;
      endPage = totalPages;
    } else {
      // more than totalPageButtons then calculate start and end pages
      // currentPage will be on the center of the paging

      if (currentPage <= Math.ceil(totalPageLinkButtons / 2)) {
        startPage = 1;
        endPage = totalPageLinkButtons;
      } else if (currentPage + Math.ceil(totalPageLinkButtons / 2) > totalPages) {
        startPage = totalPages - totalPageLinkButtons + 1;
        endPage = totalPages;
      } else {
        startPage = currentPage - Math.ceil(totalPageLinkButtons / 2) + 1;
        endPage = startPage + totalPageLinkButtons - 1;
      }
    }

    // calculate start and end item indexes
    // Indexes are started from 0 ! It is important

    const startIndex = (currentPage - 1) * pageSize;
    const endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

    const pages = [];
    // create an array of pages to ng-repeat in the pager control
    for ( let i = startPage; i <= endPage ; i++) {
      pages.Push(i);
    }

    // return object with all paging properties required by the view
    return {
      startPage           : startPage,
      endPage             : endPage,
      startIndex          : startIndex,
      endIndex            : endIndex,
      totalPageLinkButtons: totalPageLinkButtons,
      totalItems          : totalItems,
      currentPage         : currentPage,
      pageSize            : pageSize,
      totalPages          : totalPages,
      pages               : pages
    };
  }


}
7
Dr. X

独自のページネーションコンポーネントを簡単に作成できます。

プロジェクトでAngular CLIを使用する場合は、ng g c paginationを使用してアプリフォルダーに新しいコンポーネントを作成できます。AngualrCLIを使用しない場合は、フォルダーのページネーションと次のファイルを作成します。

  • pagination.ts //モデル/インターフェース用
  • pagination.component.ts //ロジック用
  • pagination.component.html // tempalte
  • pagination.component.css //スタイル

pagination.ts

export class Page {
    page: number;
    itemsPerPage: number;
}

pagination.component.ts

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Page } from './pagination';

@Component({
  selector: 'app-pagination',
  templateUrl: './pagination.component.html',
  styleUrls: ['./pagination.component.css']
})
export class PaginationComponent implements OnInit {

  @Input() maxPages: number;
  @Input() current: number;
  @Input() postsPerPage: number[];
  @Input() itemsPerPage: number;

  @Output() changePage = new EventEmitter();

  pages: any[] = [];
  pageModel: Page = {
    page: this.current,
    itemsPerPage: this.itemsPerPage
  };

  constructor() { }

  ngOnInit() {
    if (this.maxPages) {
      this.createPages();
    }
  }

  setPage(page: number, perPage: number) {
    this.pageModel.page = page;
    this.pageModel.itemsPerPage = perPage;
    this.changePage.emit(this.pageModel);
  }

  createPages() {
    for(let i=1; i <= this.maxPages; i++) {
      this.pages.Push(i);
    }
  }

}

pagination.component.html

私自身のプロジェクトではbootstrapを使用していますが、このテンプレートを簡単にカスタマイズできます。

<div class="row">
  <div class="col-lg-6">
    <nav aria-label="Pagination" *ngIf="maxPages > 1">
      <ul class="pagination">
        <li [class.disabled]="current == 1">
          <a href="javascript:;"
             (click)="setPage(current-1, itemsPerPage)"
             aria-label="Previous">
            <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        <li *ngFor="let page of pages;" [class.active]="page == current">
          <a href="javascript:;" (click)="setPage(page, itemsPerPage)">{{ page }}</a>
        </li>
        <li [class.disabled]="current == maxPages">
          <a href="javascript:;" (click)="setPage(current+1 ,itemsPerPage)" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
  </div>
  <div class="col-lg-6 text-right per-page">
    <nav aria-label="Anzahl der Beiträge pro Seite">
      <p>Anzahl der Beiträge pro Seite:</p>
      <ul class="pagination">
        <li *ngFor="let perPage of postsPerPage;" [class.active]="perPage == itemsPerPage">
          <a href="javascript:;" (click)="setPage(current, perPage)">{{ perPage }}</a>
        </li>
      </ul>
    </nav>
  </div>
</div>

pagination.component.css

ここにいくつかのスタイルがあります。

.per-page nav p {
    display: inline-block;
    margin: 25px 10px;
    font-weight: bold;
    padding: 2px 0;
}

.per-page nav .pagination {
    float: right;
}

このファイルを作成したら、このコンポーネントをapp.module.tsにインポートする必要があります。

エンドポイントのようなAPIでこのページネーションを使用する例を次に示します。

students-list.component.html

テンプレートにページ分割コンポーネントを配置し、これから放出されるevetを取得します。また、いくつかのデータを入力を介してページネーションコンポーネントに送信する必要があります。

<app-pagination [maxPages]="maxPages"
                [current]="currentPage"
                [postsPerPage]="postsPerPage"
                [itemsPerPage]="itemsPerPage"
                (changePage)="pageChanged($event)"></app-pagination>

students-list.component.tsでは、いくつかのデフォルト値を定義する必要があり、発行されたイベントを処理できます。

students-list.component.ts

itemsPerPage: number = 25;
postsPerPage: number[] = [25, 50, 100];

constructor(private studentService: StudentService) {}

pageChanged(event) {
    this.page = event.page;
    this.itemsPerPage = event.itemsPerPage
    this.loadStudentsByPage(this.page, this.itemsPerPage);
}

loadStudentsByPage(page: number, rows: number) {
    let params = new URLSearchParams(); 
    params.set('page', page.toString());
    params.set('rows', rows.toString());
    this.isLoading = true;
    this.studentService.getStudentListByParams(params).subscribe(data => {
      this.students= data;
      this.isLoading = false;
    }, error => {
      this.isLoading = false;
      console.log(error);
    });
}

students-list.service.ts

APIから学生を取得するためのサービス関数の例を次に示します。

headers = new Headers({'Content-Type': 'application/json', 'Accept': 'application/json'});

getStudentListByParams(params: URLSearchParams): Observable<StudentsModel> {
    const endpoint = domain + '/list/students';
    return this.http
      .get(endpoint, { search: params, headers: this.headers })
      .map((res: Response) => res.json())
      .catch((e) => this.handleError(e));
}

この例を使用していただければ、理解しやすくなります。

5