How can I create a pagination component in Angular

2020-05-28 11:28发布

问题:

I have a API endpoint like /list/students?page=5&rows=10 with a pagination parameters page and size. I want to create a angular2 pagination component.

Input parameters will be

  • page
  • size

In addition, I want to go to specific page and size with arrow buttons.

How can I implement this component ?

回答1:

You can crate a paging component using my below codes and services

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 is below;

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 is

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
    };
  }


}


回答2:

You can simple create your own pagination component.

If you use Angular CLI in your project you can create new component in your app folder with ng g c pagination. If you don't use Angualr CLI then create folder pagination and following files:

  • pagination.ts // for model/interface
  • pagination.component.ts // for logic
  • pagination.component.html // tempalte
  • pagination.component.css // styles

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

In my own project I use bootstrap but you can simple customize this template for you wishes.

<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

Here some styles.

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

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

After you have create this files, you should to import this component in your app.module.ts.

Here is example for using this pagination with API like your endpoint:

students-list.component.html

Put pagination component to your template and get emitted evet from this. Also you should to send some data to pagination component via input.

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

In your students-list.component.ts you should define some default values and you can work with emitted events.

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

And here is an example of service function to get students from 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));
}

I hope you can use this example and it's easy to understand.