Lógica de Paginação com Angular

Lógica de Paginação com Angular

Este é um exemplo de como implementar uma paginação em Angular 2 com uma lógica como a do Google.

Leia em 4 min

Ouvindo Strobe - deadmau5

angulartypescript

Lógica de paginação do Google

A lógica na paginação do Google é a seguinte:

Há 10 links de página mostrados a qualquer momento (por exemplo, 1 2 3 4 5 6 7 8 9 10) a menos que haja menos de 10 páginas totais o link ativo (página atual) está na 6ª posição, exceto quando o link ativo da página está abaixo de 6 ou a menos de 4 da última posição

Aqui está o que parece para cada página se houver 15 páginas totais:

01020304050607080910
01020304050607080910
01020304050607080910
01020304050607080910
01020304050607080910
01020304050607080910
02030405060708091011
03040506070809101112
04050607080910111213
05060708091011121314
06070809101112131415
06070809101112131415
06070809101112131415
06070809101112131415
06070809101112131415

Executando o Exemplo Angular 2 Localmente

Foi usado o projeto angular 2 quickstart como uma base para o aplicativo, ele é escrito em TypeScript e usa systemjs para carregar módulos. Também é possivel usar o angular-cli para o aplicativo importando os componetes e services. Se você é novo no angular 2, eu recomendaria verificar o curos de angular 2 da Loiane Groner, pois ela ensina em detalhes sobre como criar projetos com angular-cli.

  1. Instale NodeJS e NPM de nodejs.org, você pode verificar as versões que você instalou executando node -v e npm -v da linha de comando.

  2. Faça o download do código-fonte do projeto em github.com/cornflourblue/angular2-pagination-example

  3. Instale todos os pacotes necessários com npm install npm é executando a partir da linha de comando na pasta raiz do projeto (onde o package.json está localizado).

  4. Inicie o aplicativo executando npm start a partir da linha de comando na pasta raiz do projeto.

Pager Service - Lógica de paginação em TypeScript como a do Google

Para facilitar a reutilização da lógica de paginação em diferentes componentes ou módulos Angular 2, colocamos a lógica de paginação em um serviço angular 2.

import * as _ from 'underscore';

export class PagerService {
  getPager(totalItems: number, currentPage: number = 1, pageSize: number = 10) {
    // calculando o total de paginas
    let totalPages = Math.ceil(totalItems / pageSize);

    let startPage: number, endPage: number;
    if (totalPages <= 10) {
      // Se tiver menos de 10 páginas totais para mostrar tudo
      startPage = 1;
      endPage = totalPages;
    } else {
      // Se tiver mais de 10 páginas totais, calcular as páginas inicial e final
      if (currentPage <= 6) {
        startPage = 1;
        endPage = 10;
      } else if (currentPage + 4 >= totalPages) {
        startPage = totalPages - 9;
        endPage = totalPages;
      } else {
        startPage = currentPage - 5;
        endPage = currentPage + 4;
      }
    }

    // Cálculo de índices de itens iniciais e finais
    let startIndex = (currentPage - 1) * pageSize;
    let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

    // Criar um array de páginas para o ng-repeat no componente
    let pages = _.range(startPage, endPage + 1);

    // Retornar objeto com todas as propriedades exigidas para exibição
    return {
      totalItems: totalItems,
      currentPage: currentPage,
      pageSize: pageSize,
      totalPages: totalPages,
      startPage: startPage,
      endPage: endPage,
      startIndex: startIndex,
      endIndex: endIndex,
      pages: pages,
    };
  }
}
import * as _ from 'underscore';

export class PagerService {
  getPager(totalItems: number, currentPage: number = 1, pageSize: number = 10) {
    // calculando o total de paginas
    let totalPages = Math.ceil(totalItems / pageSize);

    let startPage: number, endPage: number;
    if (totalPages <= 10) {
      // Se tiver menos de 10 páginas totais para mostrar tudo
      startPage = 1;
      endPage = totalPages;
    } else {
      // Se tiver mais de 10 páginas totais, calcular as páginas inicial e final
      if (currentPage <= 6) {
        startPage = 1;
        endPage = 10;
      } else if (currentPage + 4 >= totalPages) {
        startPage = totalPages - 9;
        endPage = totalPages;
      } else {
        startPage = currentPage - 5;
        endPage = currentPage + 4;
      }
    }

    // Cálculo de índices de itens iniciais e finais
    let startIndex = (currentPage - 1) * pageSize;
    let endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1);

    // Criar um array de páginas para o ng-repeat no componente
    let pages = _.range(startPage, endPage + 1);

    // Retornar objeto com todas as propriedades exigidas para exibição
    return {
      totalItems: totalItems,
      currentPage: currentPage,
      pageSize: pageSize,
      totalPages: totalPages,
      startPage: startPage,
      endPage: endPage,
      startIndex: startIndex,
      endIndex: endIndex,
      pages: pages,
    };
  }
}

AppComponent que usa o serviço Pager

Um exemplo de componente angular 2 que usa o Pager Service acima para paginar uma lista de itens fictícios que são extraídos de um arquivo json no servidor.

import { Component, OnInit } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import * as _ from 'underscore';

import { PagerService } from './_services/index';

@Component({
  moduleId: module.id,
  selector: 'app',
  templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
  constructor(private http: Http, private pagerService: PagerService) {}

  // array com todos os itens a serem paginados
  private allItems: any[];

  // pager object
  pager: any = {};

  // items paginados
  pagedItems: any[];

  ngOnInit() {
    // pega os arquivos
    this.http
      .get('./dummy-data.json')
      .map((response: Response) => response.json())
      .subscribe((data) => {
        //Definir os itens para a resposta json
        this.allItems = data;

        //Inicializar na página 1
        this.setPage(1);
      });
  }

  setPage(page: number) {
    if (page < 1 || page > this.pager.totalPages) {
      return;
    }

    // pega o objeto pager do serviço
    this.pager = this.pagerService.getPager(this.allItems.length, page);

    // pega a página atual de itens
    this.pagedItems = this.allItems.slice(
      this.pager.startIndex,
      this.pager.endIndex + 1
    );
  }
}
import { Component, OnInit } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import * as _ from 'underscore';

import { PagerService } from './_services/index';

@Component({
  moduleId: module.id,
  selector: 'app',
  templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
  constructor(private http: Http, private pagerService: PagerService) {}

  // array com todos os itens a serem paginados
  private allItems: any[];

  // pager object
  pager: any = {};

  // items paginados
  pagedItems: any[];

  ngOnInit() {
    // pega os arquivos
    this.http
      .get('./dummy-data.json')
      .map((response: Response) => response.json())
      .subscribe((data) => {
        //Definir os itens para a resposta json
        this.allItems = data;

        //Inicializar na página 1
        this.setPage(1);
      });
  }

  setPage(page: number) {
    if (page < 1 || page > this.pager.totalPages) {
      return;
    }

    // pega o objeto pager do serviço
    this.pager = this.pagerService.getPager(this.allItems.length, page);

    // pega a página atual de itens
    this.pagedItems = this.allItems.slice(
      this.pager.startIndex,
      this.pager.endIndex + 1
    );
  }
}

HTML Template com itens paginados e navegação

Um exemplo de modelo angular 2 que mostra uma lista de itens paginados e os links de paginação para navegar entre páginas.

<div>
  <div class="container">
    <div class="text-center">
      <h1>Angular 2 - Lógica de Paginação</h1>

      <!-- Itens sendo paginados -->
      <div *ngFor="let item of pagedItems">{{item.name}}</div>

      <!-- Paginação -->
      <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
        <li [ngClass]="{disabled:pager.currentPage === 1}">
          <a (click)="setPage(1)">Início</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === 1}">
          <a (click)="setPage(pager.currentPage - 1)">Anterior</a>
        </li>
        <li
          *ngFor="let page of pager.pages"
          [ngClass]="{active:pager.currentPage === page}"
        >
          <a (click)="setPage(page)">{{page}}</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
          <a (click)="setPage(pager.currentPage + 1)">Próximo</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
          <a (click)="setPage(pager.totalPages)">Último</a>
        </li>
      </ul>
    </div>
  </div>
</div>
<div>
  <div class="container">
    <div class="text-center">
      <h1>Angular 2 - Lógica de Paginação</h1>

      <!-- Itens sendo paginados -->
      <div *ngFor="let item of pagedItems">{{item.name}}</div>

      <!-- Paginação -->
      <ul *ngIf="pager.pages && pager.pages.length" class="pagination">
        <li [ngClass]="{disabled:pager.currentPage === 1}">
          <a (click)="setPage(1)">Início</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === 1}">
          <a (click)="setPage(pager.currentPage - 1)">Anterior</a>
        </li>
        <li
          *ngFor="let page of pager.pages"
          [ngClass]="{active:pager.currentPage === page}"
        >
          <a (click)="setPage(page)">{{page}}</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
          <a (click)="setPage(pager.currentPage + 1)">Próximo</a>
        </li>
        <li [ngClass]="{disabled:pager.currentPage === pager.totalPages}">
          <a (click)="setPage(pager.totalPages)">Último</a>
        </li>
      </ul>
    </div>
  </div>
</div>

O projeto está disponível no GitHub em github.com/cornflourblue/angular2-pagination-example


Referências

Comentários