web-dev-qa-db-fra.com

Pagination du matériau 2 avec Http et DataSource

J'ai des problèmes avec la pagination des matériaux avec DataSource. Je dois récupérer du service le total des éléments de la collation, que le service REST fournit (je ne peux pas le changer). Jusqu'à présent, la seule façon de le faire était de le faire la même demande deux fois, et ce n'est tout simplement pas correct.

Si vous regardez le "servers-collection.component.ts" j'appelle un "getServiceData" juste pour obtenir le nombre total d'éléments pour la pagination ("total_items" dans la réponse à la demande). Ce que je recherche, c'est obtenir les données directement de la requête principale.

Voici la réponse brute que j'ai (GET):

{
    "_links": {
        "self": {
            "href": "https://{URL}/servers?page=1"
        },
        "first": {
            "href": "http://{URL}/servers"
        },
        "last": {
            "href": "http://{URL}/servers?page=100"
        },
        "next": {
            "href": "http://{URL}/servers?page=2"
        }
    },
    "_embedded": {
        "servers": [
            {
                "id": 1,
                "name": "Server Name",
                "ipAddress": "111.222.333.444",
                "hostName": "server.hostname.com",
                "_links": {
                    "self": {
                        "href": "http://{URL}/servers/1"
                    }
                }
            }
        ]
    },
    "page_count": 100,
    "page_size": 5,
    "total_items": 498,
    "page": 1
}

... et voici ce que j'ai fait pour y faire face:

servers-collection.component.html

<div class="example-container mat-elevation-z8">
    <mat-table #table [dataSource]="dataSource">
        <!-- ID Column -->
        <ng-container matColumnDef="id">
            <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
            <mat-cell *matCellDef="let row"> {{row.id}} </mat-cell>
        </ng-container>

        <!-- Name Column -->
        <ng-container matColumnDef="name">
            <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
            <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
        </ng-container>

        <!-- IP Address Column -->
        <ng-container matColumnDef="ipAddress">
            <mat-header-cell *matHeaderCellDef> IP Address </mat-header-cell>
            <mat-cell *matCellDef="let row"> {{row.ipAddress}} </mat-cell>
        </ng-container>

        <!-- Host Name Column -->
        <ng-container matColumnDef="hostName">
            <mat-header-cell *matHeaderCellDef> Hostname </mat-header-cell>
            <mat-cell *matCellDef="let row"> {{row.hostName}} </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 #pagination
                   [length]="length"
                   [pageSize]="pageSize"
                   [pageSizeOptions]="pageSizeOptions"
                   (page)="pageEvent = loadData($event)">
    </mat-paginator>
</div>

servers-collection.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, PageEvent } from "@angular/material";

import { ServersService } from "../../../shared/services/servers/servers.service";
import { ServersDataSource } from "../../../shared/data-source/server.datasource";

@Component({
  selector: 'app-servers-collection',
  templateUrl: './servers-collection.component.html',
  styleUrls: ['./servers-collection.component.css']
})
export class ServersCollectionComponent implements OnInit {
    // Display Data
    displayedColumns = ['id', 'name', 'ipAddress', 'hostName'];
    dataSource:ServersDataSource|null;
    pageEvent:PageEvent;

    //Pagination
    length:number;
    pageSize:number = 10;
    pageIndex:number = 1;
    pageSizeOptions:number[] = [5, 10, 25, 50, 100];

    @ViewChild(MatPaginator) pagination: MatPaginator;

    constructor(public serversService:ServersService) {
    }

    ngOnInit() {
        this.loadData();
    }

    loadData() {
        this.serversService.getServiceData(this.pageIndex, this.pageSize).subscribe(serviceData => {
                this.length = serviceData['total_items'];
            }
        );

        this.dataSource = new ServersDataSource(this.serversService, this.pagination);
    }
}

server.datasource.ts

import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import { MatPaginator } from "@angular/material";

import { Server } from "../interfaces/Server";
import { ServersService } from "../services/servers/servers.service";

export class ServersDataSource extends DataSource<any> {
    constructor(private _serverService: ServersService, private _pagination : MatPaginator) {
        super();
    }

    connect(): Observable<Server[]> {
        return this._serverService.getServers(this._pagination.pageIndex + 1, this._pagination.pageSize);
    }

    disconnect() {}
}

servers.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from "rxjs/Observable";
import { Server } from "../../interfaces/Server";
import 'rxjs/add/operator/map';

@Injectable()
export class ServersService {
    url:string = 'http://{URL}/servers';
    servers:Server[];

    constructor(private http: Http) {
    }

    getServiceData(startIndex, pageSize) {
        return this.http.get(this.url + '?page=' + startIndex + '&limit=' + pageSize)
            .map(response => response.json());
    }

    getServers(startIndex, pageSize): Observable<Server[]> {
        return this.http.get(this.url + '?page=' + startIndex + '&limit=' + pageSize)
            .map(this.extractData);
    }

    extractData(result: Response): Server[] {
        return result.json()['_embedded']['servers'];
    }
}

Merci d'avance à tous!

14
tworems

J'ai trouvé la réponse moi-même. Il s'est avéré que c'était la portée (que je ne comprenais pas correctement).

Je ne peux pas définir une variable directement à l'intérieur de l'Observer pour la classe. Ce que je peux faire, c'est appeler une méthode et lui transmettre ce dont j'ai besoin. Cela peut sembler simple, mais il m'a fallu une semaine pour arriver ici.

C'est ainsi que le codé a fini par être:

servers-collection.component.ts:

import { Component, OnInit } from '@angular/core';
import { ServersService } from "../../../shared/services/servers/servers.service";
import { ServersDataSource } from "../../../shared/data-source/server.datasource";

@Component({
    selector: 'app-servers-collection',
    templateUrl: './servers-collection.component.html',
    styleUrls: ['./servers-collection.component.css']
})
export class ServersCollectionComponent implements OnInit {
    // Data
    displayedColumns = ['id', 'name', 'ipAddress', 'hostName'];
    dataSource:ServersDataSource|null;
    data:any;

    // Pagination
    length:number;
    pageIndex:number = 1;
    pageSize:number = 10;
    pageSizeOptions:number[] = [5, 10, 25, 50, 100];

    constructor(private _serversService:ServersService) {
    }

    ngOnInit() {
        this.loadData();
    }

    loadData() {
        this.data = this._serversService.getData(this.pageIndex, this.pageSize);
        this.data.subscribe(data => {
            this.setPagination(data['total_items'], data['page'], data['page_size']);
            this.dataSource = new ServersDataSource(data['_embedded']['servers']);
        });
    }

    setPagination(length, startIndex, pageSize) {
        this.length = length;
        this.pageIndex = startIndex;
        this.pageSize = pageSize;
    }

    onPaginateChange(event) {
        this.pageIndex = event.pageIndex;
        this.pageSize = event.pageSize;
        this.loadData();
    }
}

server.datasource.ts:

import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { Server } from "../interfaces/Server";

export class ServersDataSource extends DataSource<any> {
    constructor(private _servers:Server[]) {
        super();
    }

    connect(): Observable<Server[]> {
        return Observable.of(this._servers);
    }

    disconnect() {}
}

servers.service.ts:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from "rxjs/Observable";
import 'rxjs/add/operator/map';

@Injectable()
export class ServersService {
    url:string = 'http://{URL}/servers';

    constructor(private http: Http) {
    }

    getData(startIndex, pageSize): Observable<any> {
        return this.http.get(this.url + '?page=' + startIndex + '&limit=' + pageSize)
            .map(this.extractData);
    }

    extractData(result: Response) {
        return result.json();
    }
}

J'espère que cela aide quelqu'un.

9
tworems

Merci beaucoup pour ce morceau de code. J'ai utilisé paginator comme ceci:

<mat-paginator #pagination [length]="length" 
[pageSize]="pageSize 
[pageSizeOptions]="pageSizeOptions" 
(page)="pageEvent = onPaginationChange($event)"> 
// instead of loadData($event) 
</mat-paginator>

J'ai également modifié cela depuis la première page est indexée comme 0 et sur mes données comme 1

 onPaginateChange(event) {
    this.pageIndex = event.pageIndex + 1;
    this.pageSize = event.pageSize;
    this.loadData();
}
1
Gandor