我正在尝试实现Angular Material 2,MatPaginator服务器端分页..我该如何实现?
下面是代码示例:
<div class="example-container mat-elevation-z8"> <mat-table #table [dataSource]="dataSource"> <!-- Position Column --> <ng-container matColumnDef="position"> <mat-header-cell *matHeaderCellDef> No. </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.position}} </mat-cell> </ng-container> <!-- Name Column --> <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef> Name </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell> </ng-container> <!-- Weight Column --> <ng-container matColumnDef="weight"> <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell> </ng-container> <!-- Symbol Column --> <ng-container matColumnDef="symbol"> <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> </mat-table> <mat-paginator #paginator [pageSize]="10" [pageSizeOptions]="[5,10,20]"> </mat-paginator> </div>
分页组件:
import {Component,ViewChild} from '@angular/core'; import {MatPaginator,MatTableDataSource} from '@angular/material'; /** * @title Table with pagination */ @Component({ selector: 'table-pagination-example',styleUrls: ['table-pagination-example.css'],templateUrl: 'table-pagination-example.html',}) export class TablePaginationExample { displayedColumns = ['position','name','weight','symbol']; dataSource = new MatTableDataSource<Element>(ELEMENT_DATA); @ViewChild(MatPaginator) paginator: MatPaginator; /** * Set the paginator after the view init since this component will * be able to query its view for the initialized paginator. */ ngAfterViewInit() { this.dataSource.paginator = this.paginator; } } export interface Element { name: string; position: number; weight: number; symbol: string; } const ELEMENT_DATA: Element[] = [ {position: 1,name: 'Hydrogen',weight: 1.0079,symbol: 'H'},{position: 2,name: 'Helium',weight: 4.0026,symbol: 'He'},{position: 3,name: 'Lithium',weight: 6.941,symbol: 'Li'},{position: 4,name: 'Beryllium',weight: 9.0122,symbol: 'Be'},{position: 5,name: 'Boron',weight: 10.811,symbol: 'B'},{position: 6,name: 'Carbon',weight: 12.0107,symbol: 'C'},{position: 7,name: 'Nitrogen',weight: 14.0067,symbol: 'N'},{position: 8,name: 'Oxygen',weight: 15.9994,symbol: 'O'},{position: 9,name: 'Fluorine',weight: 18.9984,symbol: 'F'},{position: 10,name: 'Neon',weight: 20.1797,symbol: 'Ne'},{position: 11,name: 'Sodium',weight: 22.9897,symbol: 'Na'},{position: 12,name: 'Magnesium',weight: 24.305,symbol: 'Mg'},{position: 13,name: 'Aluminum',weight: 26.9815,symbol: 'Al'},{position: 14,name: 'Silicon',weight: 28.0855,symbol: 'Si'},{position: 15,name: 'Phosphorus',weight: 30.9738,symbol: 'P'},{position: 16,name: 'Sulfur',weight: 32.065,symbol: 'S'},{position: 17,name: 'Chlorine',weight: 35.453,symbol: 'Cl'},{position: 18,name: 'Argon',weight: 39.948,symbol: 'Ar'},{position: 19,name: 'Potassium',weight: 39.0983,symbol: 'K'},{position: 20,name: 'Calcium',weight: 40.078,symbol: 'Ca'},];
如何实现服务器端分页,这将触发下一页单击或页面大小更改的更改事件以获取下一组记录.
https://stackblitz.com/angular/qxxpqbqolyb?file=app%2Ftable-pagination-example.ts
有人请?
根据Wilfredo的回答(
https://stackoverflow.com/a/47994113/986160),我编写了一个完整的工作示例,因为有些部分也没有问题.这是使用Angular 5和Material Design进行服务器端分页和排序的更一般情况(仍然需要插入过滤) – 希望它对某人有用:
分页组件:
import { ViewChild,Component,Inject,OnInit,AfterViewInit } from '@angular/core'; import { EntityJson } from './entity.json'; import { EntityService } from './entity.service'; import { MatPaginator,MatSort,MatTableDataSource } from '@angular/material'; import { Observable } from 'rxjs/Observable'; import { merge } from 'rxjs/observable/merge'; import { of as observableOf } from 'rxjs/observable/of'; import { catchError } from 'rxjs/operators/catchError'; import { map } from 'rxjs/operators/map'; import { startWith } from 'rxjs/operators/startWith'; import { switchMap } from 'rxjs/operators/switchMap'; @Component({ selector: 'entity-latest-page',providers: [EntityService],styles: [` :host mat-table { display: flex; flex-direction: column; min-width: 100px; max-width: 800px; margin: 0 auto; } `],template: `<mat-card> <mat-card-title>Entity List <button mat-button [routerLink]="['/create/entity']"> CREATE </button> </mat-card-title> <mat-card-content> <mat-table #table matSort [dataSource]="entitiesDataSource" matSort class="mat-elevation-z2"> <ng-container matColumnDef="id"> <mat-header-cell *matHeaderCellDef mat-sort-header> Id </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.id}} </mat-cell> </ng-container> <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell> </ng-container> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> </mat-table> </mat-card-content> <mat-card-content> <mat-paginator #paginator [length]="resultsLength" [pageSize]="5" [pageSizeOptions]="[5,20]"> </mat-paginator> </mat-card-content> </mat-card> ` }) export class EntityLatestPageComponent implements AfterViewInit { private entities: EntityJson[]; private entitiesDataSource: MatTableDataSource<EntityJson> = new MatTableDataSource(); private displayedColumns = ['id','name']; resultsLength = 0; isLoadingResults = false; isRateLimitReached = false; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; public constructor( @Inject(EntityService) private entityService: EntityService) { } public ngAfterViewInit() { // If the user changes the sort order,reset back to the first page. this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0); merge(this.sort.sortChange,this.paginator.page) .pipe( startWith({}),switchMap(() => { this.isLoadingResults = true; return this.entityService.fetchLatest(this.sort.active,this.sort.direction,this.paginator.pageIndex + 1,this.paginator.pageSize,(total) => this.resultsLength = total); }),map(data => { this.isLoadingResults = false; this.isRateLimitReached = false; //alternatively to response headers; //this.resultsLength = data.total; return data; }),catchError(() => { this.isLoadingResults = false; this.isRateLimitReached = true; return observableOf([]); }) ).subscribe(data => this.entitiesDataSource.data = data); } }
服务:
import { EntityJson } from './entity.json'; import { ApiHelper } from '../common/api.helper'; import { Http,Headers,Response,RequestOptions } from '@angular/http'; import { Inject,Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { AuthenticationService } from '../auth/authentication.service'; import { stringify } from 'query-string'; @Injectable() export class EntityService { private options: RequestOptions; private apiPrefix: string; private apiEndpoint: string; constructor( @Inject(Http) private http: Http,@Inject(AuthenticationService) private authService: AuthenticationService) { this.options = authService.prepareRequestHeaders(); this.apiPrefix = 'http://localhost:4200/api/v1/'; this.apiEndpoint = this.apiPrefix + 'entities'; } public fetchLatest(sort: string = '',order: string = '',page: number = 1,perPage: number = 5,initTotal: Function = () => {}): Observable<EntityJson[]> { return this.http.get(this.apiEndpoint +'?' + EntityService.createUrlQuery({sort: {field: sort,order: order},pagination: { page,perPage }}),this.options) .map((res) => { const total = res.headers.get('x-total-count').split('/').pop(); initTotal(total); return JSON.parse(res.text()).content }); } //should be put in a util static createUrlQuery(params: any) { if (!params) { return ""; } let page; let perPage; let field; let order; let query: any = {}; if (params.pagination) { page = params.pagination.page; perPage = params.pagination.perPage; query.range = JSON.stringify([ page,perPage,]); } if (params.sort) { field = params.sort.field; order = params.sort.order; if (field && order) { query.sort = JSON.stringify([field,order]); } else { query.sort = JSON.stringify(['id','ASC']); } } if (!params.filter) { params.filter = {}; } if (Array.isArray(params.ids)) { params.filter.id = params.ids; } if (params.filter) { query.filter = JSON.stringify(params.filter) } console.log(query,stringify(query)); return stringify(query); } }
Spring Boot Rest控制器端点
@GetMapping("entities") public Iterable<Entity> filterBy( @RequestParam(required = false,name = "filter") String filterStr,@RequestParam(required = false,name = "range") String rangeStr,name="sort") String sortStr) { //my own helpers - for source: https://github.com/zifnab87/react-admin-java-rest //FilterWrapper wrapper = filterService.extractFilterWrapper(filterStr,rangeStr,sortStr); //return filterService.filterBy(wrapper,repo); }
一些说明:
>确保导入模块:MatTableModule,MatPaginatorModule和MatSortModule以及Material Design的其他模块.>我决定从Response-Header x-total-count填充resultsLength(total),我通过Spring Boot @ControllerAdvice填充它.或者,您可以从EntityService返回的对象(例如,Spring for Spring)获取此信息,但这意味着如果您想要“生成”,则需要使用any作为返回类型或为项目中的所有实体声明包装类对象.类型安全”.