ngx-pagination:Angular 6 服务器端实现

Posted

技术标签:

【中文标题】ngx-pagination:Angular 6 服务器端实现【英文标题】:ngx-pagination: Angular 6 server side implementation 【发布时间】:2019-03-22 10:54:00 【问题描述】:

我正在尝试使用 ngx-pagination 在我的 Angular 6 应用程序上实现服务器端分页。

我已尽我所能关注documentation,但遇到以下问题,不知道如何进行。

问题

    组件从 api 加载并获取数据,但直到 之后 才会在渲染上显示我会通过导航到下一页然后再调用 api 两次到上一个。

    api第二页的数据没有被调用。

截图

初始页面加载

来回导航后

示例代码

import  Component, OnInit, Input, ChangeDetectionStrategy  from '@angular/core';
import  Http, Response  from '@angular/http';
import  ApiService  from '../../services/api.service';
import  SiteUrls  from '../../services/constants.service';
import  Observable  from 'rxjs/Observable';
import  of  from 'rxjs';
import  map, tap  from 'rxjs/operators';
import 'rxjs/add/operator/delay';

interface IServerResponse 
    items: any[];
    total: number;


@Component(
    selector: 'app-sample',
    templateUrl: './sample.component.html',
    styleUrls: ['./sample.component.scss'],
    changeDetection: ChangeDetectionStrategy.OnPush
)

export class SampleComponent implements OnInit 

    @Input() sample: any = [];
    total: number;
    p = 1;
    pagedItems: Observable<any[]>;
    public meta: any = ;
    constructor(private site: SiteUrls, private http: Http, private api: ApiService) 

    ngOnInit() 
        this.getPage(1);
    

    async getPage(page: number) 
        this.pagedItems = this.serverCall(this.sample, page)
            .pipe(tap((res) => 
                this.total = res.total;
                this.p = page;
                console.log('total', this.total, 'page', this.p, 'res', res);

            )).pipe(map((res) => res.items));
    

    serverCall(sample: any[], page: number): Observable<IServerResponse> 
        this.getsample();
        const perPage = this.meta.per_page;
        const start = (page - 1) * perPage;
        const end = start + perPage;
        return of(
                items: sample.slice(start, end),
                total: this.meta.total
            ).delay(1000);
    

   private getsample() 
        this.api.get('sample').subscribe((data) => 
            this.sample = data.body.data;
            this.meta = data.body.meta;
        );
    
 <tbody>
                <tr *ngFor="let tran of pagedItems | async | paginate:  itemsPerPage: meta.per_page, currentPage: p, totalItems: meta.total ">
                 
                  <td>
                    tran.account.number
                  </td>
                  <td>
                    tran.sender.name
                  </td>
                  <td>
                    tran.recipient.name
                  </td>
                  <td>
                    tran.date | date: 'MMMM dd, yyyy'
                  </td>
                  <td style="background-color: antiquewhite">
                    tran.subtotal | currency
                  </td>
                  <td style="background-color: antiquewhite">
                    tran.fee | currency
                  </td>
                  <td style="background-color: antiquewhite">
                    <b>tran.total | currency</b>
                  </td>
                </tr>
              </tbody>
            </table>
            <pagination-controls (pageChange)="getPage($event)"></pagination-controls>

任何帮助将不胜感激。

更新

getsample() 正在页面加载时执行,api 返回数据。 为了安全起见,我将方法更改为async,现在看起来像这样:

async getsample() 
   try 
       await this.api.get('sample').subscribe((data) => 
        this.sample = data.body.data;
        this.meta = data.body.meta;
       );
    catch (error) 
  

我也实现了布兰登给出的答案,但问题仍然存在。

【问题讨论】:

我认为问题在于 this.getsample() 订阅尚未执行(因此 samplemeta 未设置)并且您正在尝试读取这些属性(在 serverCall(...) 中)。这是async 问题。 谢谢@miselking,我感觉可能是问题所在。我在下面尝试了布兰登的建议,但没有奏效。您还有其他解决方案吗? 【参考方案1】:

您的代码还有更多问题,其中之一是您对 this.getsample(); 的异步调用,但您无需等待结果。

另一件事是你不能等待 observable。首先通过.toPromise() 将其转换为promise,而不是订阅,或者根本不使用promise 而是订阅(但仅在最顶层 - 在ngOnInit 处理程序中)。

使用异步/等待:

async ngOnInit() 
    await this.getsample(); // move the loading here
    await this.getPage(1);


async getPage(page: number) 
    const res = await this.serverCall(this.sample, page);
    this.total = res.total;
    this.p = page;
    console.log('total', this.total, 'page', this.p, 'res', res);
    this.pagedItems = res.items;


async serverCall(sample: any[], page: number): Promise<IServerResponse> 
    const perPage = this.meta.per_page;
    const start = (page - 1) * perPage;
    const end = start + perPage;
    return of(
        items: sample.slice(start, end),
        total: this.meta.total
    ).delay(1000).toPromise(); // convert the observable to promise


private async getsample() 
    const data = await this.api.get('sample').toPromise(); // and again here
    this.sample = data.body.data;
    this.meta = data.body.meta;

【讨论】:

这让我更接近修复,谢谢。问题是我不能在 Promise 上使用 AsyncPipe,但也许我不会。 pagedItems 的 items 数组仍然返回空。 你绝对可以在 promise 上使用异步管道 好的,因为我对这个很陌生,所以我需要引导我完成这个。我已经实现了您的答案,但打字稿抱怨我无法将类型 any 分配给 Observable。 @马丁 您的代码中可能仍有一些错误的类型提示(我在 main 中没有使用Observable 类型提示,因此错误不是由它引起的)。顺便说一句,我想我发现了你的问题。在getPage 方法中使用它之后,您正在调用getsample() - 您需要先加载它。 然后将 getsample 调用移动到 getPage 方法的第一行【参考方案2】:

这是一个异步/等待问题。

ngOnInit() 
  this.getPage(1);

应该是:

async ngOnInit() 
  await this.getPage(1);

否则,this.pagedItems 将在 serverCall() 完成之前为空。

【讨论】:

感谢@Brandon 的帮助,但不幸的是,这并没有解决问题。

以上是关于ngx-pagination:Angular 6 服务器端实现的主要内容,如果未能解决你的问题,请参考以下文章

使用 ngx-pagination 的服务器端分页

Angular,TypeError:无法读取未定义的属性“排序”

ngx-pagination - 将分页重置为第一页

将 ngx-pagination 实现为自定义组件

与 ngx-pagination 一起使用时,ngFor 索引重置为 0

多个ngx分页错误-角度2