<!DOCTYPE html>
<html>
<head>
<base href="." />
<script data-require="lodash.js@4.16.2" data-semver="4.16.2" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="https://unpkg.com/core-js@2.4.1/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js/dist/zone.js"></script>
<script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
<script src="config.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<div class="container">
<my-app>
loading...
</my-app>
</div>
</body>
</html>
/* Styles go here */
# Angular2 - Tables with patination buttons
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { BlahService } from './blahService';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { PaginationComponent } from './pagination-buttons/pagination-buttons.component';
import { TakePipe, DropPipe, LengthPipe } from './pipes/collections.pipe';
@NgModule({
imports: [
BrowserModule
, HttpModule
],
declarations: [
AppComponent
, PaginationComponent
, TakePipe
, DropPipe
, LengthPipe
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
//our root app component
import { Component } from '@angular/core';
import { BlahService } from './blahService';
import { PaginationComponent } from './pagination-buttons/pagination-buttons.component';
@Component({
selector: 'my-app',
providers: [ BlahService ],
templateUrl: 'src/app.component.html'
})
export class AppComponent {
private blahs = [];
private activePage = 1;
private readonly chunkListSize = 8;
constructor(private blahService: BlahService) {
blahService.blahs.subscribe(blahs => this.blahs = blahs);
}
private onChange(): void {
this.activePage = 1;
}
private updateSelectedPage(idPage: number){
this.activePage = idPage;
}
}
//a simple service
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/Rx';
@Injectable()
export class BlahService {
private blahs;
constructor(http: Http) {
this.blahs = http.get('data/blah.json').map(res => res.json());
}
public blahs() {
return this.blahs;
}
}
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
paths: {
'npm:': 'https://unpkg.com/'
},
//map tells the System loader where to look for things
map: {
'app': './src',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs',
'typescript': 'npm:typescript@2.0.2/lib/typescript.js',
'lodash': 'npm:lodash'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
}
}
});
[
{
"name": "Rosanne Hammond",
"company": "YOGASM",
"email": "rosannehammond@yogasm.com"
},
{
"name": "Lydia Diaz",
"company": "STOCKPOST",
"email": "lydiadiaz@stockpost.com"
},
{
"name": "Macias Hopper",
"company": "OPTYK",
"email": "maciashopper@optyk.com"
},
{
"name": "Beverly Sandoval",
"company": "NAMEGEN",
"email": "beverlysandoval@namegen.com"
},
{
"name": "Althea Peck",
"company": "ZOLARITY",
"email": "altheapeck@zolarity.com"
},
{
"name": "Desiree Barrett",
"company": "PASTURIA",
"email": "desireebarrett@pasturia.com"
},
{
"name": "Tamera Carrillo",
"company": "COREPAN",
"email": "tameracarrillo@corepan.com"
},
{
"name": "Lana Haney",
"company": "ZEROLOGY",
"email": "lanahaney@zerology.com"
},
{
"name": "Cassandra Santana",
"company": "INSURESYS",
"email": "cassandrasantana@insuresys.com"
},
{
"name": "Calderon Morrow",
"company": "JIMBIES",
"email": "calderonmorrow@jimbies.com"
},
{
"name": "Harmon Cooley",
"company": "HOTCAKES",
"email": "harmoncooley@hotcakes.com"
},
{
"name": "Olson Obrien",
"company": "MOMENTIA",
"email": "olsonobrien@momentia.com"
},
{
"name": "Sawyer Sweet",
"company": "FITCORE",
"email": "sawyersweet@fitcore.com"
},
{
"name": "Witt Day",
"company": "SNACKTION",
"email": "wittday@snacktion.com"
},
{
"name": "Williamson Hardin",
"company": "BULLJUICE",
"email": "williamsonhardin@bulljuice.com"
},
{
"name": "Isabel Barlow",
"company": "EXTRAWEAR",
"email": "isabelbarlow@extrawear.com"
},
{
"name": "Lucia Schneider",
"company": "LOVEPAD",
"email": "luciaschneider@lovepad.com"
},
{
"name": "Riddle Snow",
"company": "EXTRAGENE",
"email": "riddlesnow@extragene.com"
},
{
"name": "Karyn Alvarez",
"company": "GINK",
"email": "karynalvarez@gink.com"
},
{
"name": "Danielle Petty",
"company": "GOGOL",
"email": "daniellepetty@gogol.com"
},
{
"name": "Saunders Dalton",
"company": "PULZE",
"email": "saundersdalton@pulze.com"
},
{
"name": "Karin Nelson",
"company": "PREMIANT",
"email": "karinnelson@premiant.com"
},
{
"name": "Candace Chaney",
"company": "MUSANPOLY",
"email": "candacechaney@musanpoly.com"
},
{
"name": "Randi Jordan",
"company": "SENMEI",
"email": "randijordan@senmei.com"
},
{
"name": "Shaw Lindsey",
"company": "QUONK",
"email": "shawlindsey@quonk.com"
},
{
"name": "Jocelyn Mercado",
"company": "NORSUP",
"email": "jocelynmercado@norsup.com"
},
{
"name": "Leila Summers",
"company": "BITTOR",
"email": "leilasummers@bittor.com"
},
{
"name": "Pickett Coffey",
"company": "NSPIRE",
"email": "pickettcoffey@nspire.com"
},
{
"name": "Richards Mills",
"company": "REVERSUS",
"email": "richardsmills@reversus.com"
},
{
"name": "Ronda Parks",
"company": "OLUCORE",
"email": "rondaparks@olucore.com"
},
{
"name": "Montoya Mcintyre",
"company": "TALKOLA",
"email": "montoyamcintyre@talkola.com"
},
{
"name": "Cline Stone",
"company": "SHEPARD",
"email": "clinestone@shepard.com"
},
{
"name": "Robin Chapman",
"company": "RENOVIZE",
"email": "robinchapman@renovize.com"
},
{
"name": "Bauer Head",
"company": "VIXO",
"email": "bauerhead@vixo.com"
},
{
"name": "Ida Barton",
"company": "PHOLIO",
"email": "idabarton@pholio.com"
},
{
"name": "Tonya Powers",
"company": "MANGLO",
"email": "tonyapowers@manglo.com"
},
{
"name": "Rosalyn Pacheco",
"company": "CAXT",
"email": "rosalynpacheco@caxt.com"
},
{
"name": "Janette Hodge",
"company": "POLARIUM",
"email": "janettehodge@polarium.com"
},
{
"name": "Willis Moran",
"company": "ROCKABYE",
"email": "willismoran@rockabye.com"
},
{
"name": "Ebony Harris",
"company": "LINGOAGE",
"email": "ebonyharris@lingoage.com"
},
{
"name": "Cooper Jennings",
"company": "CALCULA",
"email": "cooperjennings@calcula.com"
},
{
"name": "Alvarez Allen",
"company": "KRAGGLE",
"email": "alvarezallen@kraggle.com"
},
{
"name": "Elvia Ware",
"company": "DAIDO",
"email": "elviaware@daido.com"
},
{
"name": "Rosetta Stein",
"company": "XPLOR",
"email": "rosettastein@xplor.com"
},
{
"name": "Patti Conway",
"company": "BOLAX",
"email": "patticonway@bolax.com"
},
{
"name": "Kline Terry",
"company": "BIFLEX",
"email": "klineterry@biflex.com"
},
{
"name": "Arnold Chase",
"company": "DAYCORE",
"email": "arnoldchase@daycore.com"
},
{
"name": "Whitney Cardenas",
"company": "MOREGANIC",
"email": "whitneycardenas@moreganic.com"
},
{
"name": "Levine Cash",
"company": "MAROPTIC",
"email": "levinecash@maroptic.com"
},
{
"name": "Diann Wade",
"company": "GEEKMOSIS",
"email": "diannwade@geekmosis.com"
},
{
"name": "Terrell Lynn",
"company": "KINDALOO",
"email": "terrelllynn@kindaloo.com"
},
{
"name": "Deana Keller",
"company": "INTERLOO",
"email": "deanakeller@interloo.com"
},
{
"name": "Jewell Thompson",
"company": "SINGAVERA",
"email": "jewellthompson@singavera.com"
},
{
"name": "Billie Herring",
"company": "ENERSOL",
"email": "billieherring@enersol.com"
},
{
"name": "Lesley Farmer",
"company": "DANCERITY",
"email": "lesleyfarmer@dancerity.com"
},
{
"name": "Hickman Lane",
"company": "VETRON",
"email": "hickmanlane@vetron.com"
},
{
"name": "Janine Stanley",
"company": "EPLODE",
"email": "janinestanley@eplode.com"
},
{
"name": "Washington Buckner",
"company": "RODEOMAD",
"email": "washingtonbuckner@rodeomad.com"
},
{
"name": "Pearson Knapp",
"company": "AQUAFIRE",
"email": "pearsonknapp@aquafire.com"
},
{
"name": "Mayer Meyers",
"company": "KLUGGER",
"email": "mayermeyers@klugger.com"
},
{
"name": "Pena Short",
"company": "FLUM",
"email": "penashort@flum.com"
},
{
"name": "Darcy Cooke",
"company": "NETAGY",
"email": "darcycooke@netagy.com"
},
{
"name": "Chandra Ewing",
"company": "NIKUDA",
"email": "chandraewing@nikuda.com"
},
{
"name": "Gomez Stevens",
"company": "COASH",
"email": "gomezstevens@coash.com"
},
{
"name": "Janie Macias",
"company": "PERKLE",
"email": "janiemacias@perkle.com"
},
{
"name": "Lindsay Harvey",
"company": "QIAO",
"email": "lindsayharvey@qiao.com"
},
{
"name": "Queen Stafford",
"company": "STUCCO",
"email": "queenstafford@stucco.com"
},
{
"name": "Austin Pittman",
"company": "DOGNOSIS",
"email": "austinpittman@dognosis.com"
},
{
"name": "Noelle Rowland",
"company": "ZOARERE",
"email": "noellerowland@zoarere.com"
},
{
"name": "Heather Finley",
"company": "AQUOAVO",
"email": "heatherfinley@aquoavo.com"
},
{
"name": "Ursula Fulton",
"company": "NEBULEAN",
"email": "ursulafulton@nebulean.com"
},
{
"name": "Louisa Oneill",
"company": "TELLIFLY",
"email": "louisaoneill@tellifly.com"
},
{
"name": "Mitchell Johns",
"company": "PLUTORQUE",
"email": "mitchelljohns@plutorque.com"
},
{
"name": "John Cole",
"company": "INSECTUS",
"email": "johncole@insectus.com"
},
{
"name": "Cathy Gibbs",
"company": "EQUITAX",
"email": "cathygibbs@equitax.com"
},
{
"name": "Randall Shields",
"company": "CENTREXIN",
"email": "randallshields@centrexin.com"
},
{
"name": "Keith Ashley",
"company": "EVENTAGE",
"email": "keithashley@eventage.com"
},
{
"name": "Foster Simon",
"company": "ROCKLOGIC",
"email": "fostersimon@rocklogic.com"
},
{
"name": "Shannon Rodriquez",
"company": "VISALIA",
"email": "shannonrodriquez@visalia.com"
},
{
"name": "Rios Mcconnell",
"company": "PROSELY",
"email": "riosmcconnell@prosely.com"
},
{
"name": "Alta Cleveland",
"company": "EMTRAC",
"email": "altacleveland@emtrac.com"
},
{
"name": "Alvarado Acosta",
"company": "EXTRO",
"email": "alvaradoacosta@extro.com"
},
{
"name": "Kim Mckinney",
"company": "EXIAND",
"email": "kimmckinney@exiand.com"
},
{
"name": "Simone Spears",
"company": "DYMI",
"email": "simonespears@dymi.com"
},
{
"name": "Mabel Fleming",
"company": "OPTIQUE",
"email": "mabelfleming@optique.com"
},
{
"name": "Cecilia Hahn",
"company": "SONGBIRD",
"email": "ceciliahahn@songbird.com"
},
{
"name": "Rollins Payne",
"company": "IMAGINART",
"email": "rollinspayne@imaginart.com"
},
{
"name": "Barrett Cortez",
"company": "SEQUITUR",
"email": "barrettcortez@sequitur.com"
},
{
"name": "Gallegos Bean",
"company": "VOLAX",
"email": "gallegosbean@volax.com"
},
{
"name": "Leslie Harrison",
"company": "TECHMANIA",
"email": "leslieharrison@techmania.com"
},
{
"name": "Carrillo Aguirre",
"company": "COMBOGENE",
"email": "carrilloaguirre@combogene.com"
},
{
"name": "Haley Hayden",
"company": "REPETWIRE",
"email": "haleyhayden@repetwire.com"
},
{
"name": "Potts Vaughan",
"company": "PYRAMIA",
"email": "pottsvaughan@pyramia.com"
},
{
"name": "Holder Hancock",
"company": "POOCHIES",
"email": "holderhancock@poochies.com"
},
{
"name": "Lea Beasley",
"company": "ONTALITY",
"email": "leabeasley@ontality.com"
},
{
"name": "Noel Rogers",
"company": "VISUALIX",
"email": "noelrogers@visualix.com"
},
{
"name": "Dodson Faulkner",
"company": "MAXIMIND",
"email": "dodsonfaulkner@maximind.com"
},
{
"name": "Peters Mccall",
"company": "QUAILCOM",
"email": "petersmccall@quailcom.com"
},
{
"name": "Elise Christensen",
"company": "ACCEL",
"email": "elisechristensen@accel.com"
},
{
"name": "Monroe Hogan",
"company": "ANACHO",
"email": "monroehogan@anacho.com"
},
{
"name": "Lora Snider",
"company": "EXOSPEED",
"email": "lorasnider@exospeed.com"
},
{
"name": "Leach Whitaker",
"company": "VENDBLEND",
"email": "leachwhitaker@vendblend.com"
},
{
"name": "Kristin Bass",
"company": "ECRAZE",
"email": "kristinbass@ecraze.com"
},
{
"name": "Christa Aguilar",
"company": "NETERIA",
"email": "christaaguilar@neteria.com"
},
{
"name": "Maxine Jacobson",
"company": "FANGOLD",
"email": "maxinejacobson@fangold.com"
},
{
"name": "Lourdes Mayo",
"company": "JOVIOLD",
"email": "lourdesmayo@joviold.com"
},
{
"name": "Ramirez Ward",
"company": "BOINK",
"email": "ramirezward@boink.com"
},
{
"name": "Mejia Rodgers",
"company": "FOSSIEL",
"email": "mejiarodgers@fossiel.com"
},
{
"name": "Kirby Rocha",
"company": "RODEMCO",
"email": "kirbyrocha@rodemco.com"
},
{
"name": "Maryellen Mckenzie",
"company": "KOG",
"email": "maryellenmckenzie@kog.com"
},
{
"name": "Rochelle Tate",
"company": "CIRCUM",
"email": "rochelletate@circum.com"
},
{
"name": "Collins Thomas",
"company": "TEMORAK",
"email": "collinsthomas@temorak.com"
},
{
"name": "Tanisha Graham",
"company": "CINCYR",
"email": "tanishagraham@cincyr.com"
},
{
"name": "Kelly Schultz",
"company": "SAVVY",
"email": "kellyschultz@savvy.com"
},
{
"name": "Shawn Bowen",
"company": "ACRODANCE",
"email": "shawnbowen@acrodance.com"
},
{
"name": "Daniels Bruce",
"company": "ISOLOGICS",
"email": "danielsbruce@isologics.com"
},
{
"name": "Juliet Washington",
"company": "EMERGENT",
"email": "julietwashington@emergent.com"
},
{
"name": "Fannie Graves",
"company": "EXOSTREAM",
"email": "fanniegraves@exostream.com"
},
{
"name": "Jarvis Suarez",
"company": "FLEXIGEN",
"email": "jarvissuarez@flexigen.com"
},
{
"name": "Kane Lloyd",
"company": "QUORDATE",
"email": "kanelloyd@quordate.com"
},
{
"name": "Mueller Nicholson",
"company": "OATFARM",
"email": "muellernicholson@oatfarm.com"
},
{
"name": "Roxanne Mays",
"company": "ZIDANT",
"email": "roxannemays@zidant.com"
},
{
"name": "Kirk English",
"company": "ERSUM",
"email": "kirkenglish@ersum.com"
},
{
"name": "Bobbi Santiago",
"company": "ARCHITAX",
"email": "bobbisantiago@architax.com"
},
{
"name": "Elisabeth Garrison",
"company": "ONTAGENE",
"email": "elisabethgarrison@ontagene.com"
},
{
"name": "Lynch Garrett",
"company": "DIGIAL",
"email": "lynchgarrett@digial.com"
},
{
"name": "Chambers Brooks",
"company": "COMTEXT",
"email": "chambersbrooks@comtext.com"
},
{
"name": "Juliette Campbell",
"company": "BOILICON",
"email": "juliettecampbell@boilicon.com"
},
{
"name": "Shepherd Castro",
"company": "FRENEX",
"email": "shepherdcastro@frenex.com"
},
{
"name": "Darla Roach",
"company": "INFOTRIPS",
"email": "darlaroach@infotrips.com"
},
{
"name": "Weber Singleton",
"company": "DIGIFAD",
"email": "webersingleton@digifad.com"
},
{
"name": "Meyers Sherman",
"company": "IMKAN",
"email": "meyerssherman@imkan.com"
},
{
"name": "Rivas Conley",
"company": "KOOGLE",
"email": "rivasconley@koogle.com"
}
]
import { Component, Input, Output, EventEmitter } from "@angular/core";
import * as _ from "lodash";
@Component({
selector: 'pagination-buttons',
templateUrl: 'src/pagination-buttons/pagination-buttons.component.html',
styleUrls: ['src/pagination-buttons/pagination-buttons.component.css']
})
export class PaginationComponent {
private activePage: number;
@Input() collectionSize: number;
@Input() chunkSize: number;
@Output() selectedPageChange: EventEmitter<number> = new EventEmitter();
@Input()
get selectedPage() { return this.activePage; }
set selectedPage(val: number){
this.activePage = val;
this.selectedPageChange.emit(val);
}
constructor(){}
private paginationButtonClick(id: string): void {
this.activePage = parseInt(id);
this.selectedPageChange.emit(this.activePage);
}
private movePagination(inc: number): void {
this.paginationButtonClick((this.activePage+inc).toString());
}
private paginate(activePage: string, size: number): string[] {
const length = Math.ceil(size/this.chunkSize);
return Pagination.paginate(length)(parseInt(activePage));
}
private paginate(activePage, size) : string[] {
size = Math.ceil(size);
if (size == 0){
return [];
} else if (size <= 10) {
return _.range(1, size+1).map( i => i.toString() );
} else if (size > 10 && activePage <= 5) {
return _.range(1, 8)
.map( i => i.toString() )
.concat("..")
.concat( _.range(size -1, size+1).map( i => i.toString() ));
} else if (activePage >= size -5) {
return _.range(1, 3)
.map( i => i.toString() )
.concat("..")
.concat( _.range(size -6, size+1).map( i => i.toString() ));
} else {
return _.range(1, 3)
.map( i => i.toString() )
.concat("..")
.concat( _.range(activePage-1, activePage+3).map( i => i.toString() ))
.concat("..")
.concat( _.range(size-1, size+1) );
}
}
}
.Pagination {
position: initial;
}
/* Workaround to cancel href on the view, preventing
* refreshing the parent page if we use href='#' */
a:not([href]){
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none
}
a.disabled {
pointer-events: none;
cursor: default;
}
import { Pipe, PipeTransform } from '@angular/core';
import * as _ from "lodash";
@Pipe({name: 'length'})
export class LengthPipe implements PipeTransform {
transform(collection: any[]): number {
return collection.length;
}
}
@Pipe({name: 'drop'})
export class DropPipe implements PipeTransform {
transform(collection: any[], n: number): any[] {
return _.drop(collection, n);
}
}
@Pipe({name: 'take'})
export class TakePipe implements PipeTransform {
transform(collection: any[], n: number): any[] {
return _.take(collection, n);
}
}
<ul class="pagination">
<li [class.disabled]="activePage === 1">
<a (click)="movePagination(-1)" [class.disabled]="activePage === 1">«</a>
</li>
<li [class.active]="activePage == i" *ngFor="let i of paginate(activePage, collectionSize / chunkSize)">
<a (click)="paginationButtonClick(i)" [class.disabled]="i === '..'">{{i}}</a>
</li>
<li [class.disabled]="activePage >= collectionSize / chunkSize">
<a (click)="movePagination(1)" [class.disabled]="activePage >= collectionSize / chunkSize">»</a>
</li>
</ul>
<div class="container">
<h2>This is a table with pagination buttons</h2>
<div class="row">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Company</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let blah of (blahs | drop : ((activePage-1)*chunkListSize) | take: chunkListSize )">
<td>{{blah.name}}</td>
<td>{{blah.company}}</td>
<td>{{blah.email}}</td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<pagination-buttons
[(selectedPage)]="activePage"
[chunkSize]="chunkListSize"
[collectionSize]="( blahs | length )">
</pagination-buttons>
</div>
</div>