简体   繁体   中英

How to set server side pagination in Angular material Table using token

here i have a issue while working with angular paginator. here i am getting data like below

Response One:

{
    "Tabledata": [
      {
        "firstName":"Samuel",
        "lastName":"Smith"
      },
      {
        "firstName":"Sanu",
        "lastName":"Smith"
      }
    ],
    "paging": {
        "RecordsCount": 2,
        "token": "JhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
    }
}

Response Two: I am getting total records count as 50

 { 
    'RecordsCount' : 50
  }

Now in the initial call the i am calling api and the api format is below

Initial Call

http://some api.com/data?searchParams=&pageSize=2&token=

After calling this i will get response like below

{
        "Tabledata": [
          {
            "firstName":"Samuel",
            "lastName":"Smith"
          },
          {
            "firstName":"Sanu",
            "lastName":"Smith"
          }
        ],
        "paging": {
            "RecordsCount": 2,
            "token": "JhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
        }
    }

and after pressing the next button the api should initiate another http call and use this token and send it params for the same api like below

2nd call

http://some api.com/data?searchParams=&pageSize=2&token=JhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

After this call i will get again same response but here token changes

{
            "Tabledata": [
              {
                "firstName":"Samuel",
                "lastName":"Smith"
              },
              {
                "firstName":"Sanu",
                "lastName":"Smith"
              }
            ],
            "paging": {
                "RecordsCount": 2,
                "token": "abcd"
            }
        }

And if i press next again in the 3rd api call is should use the 2nd response token as param for the 3rd call and it will give some token and if user presses Prev then it should use that tocken and send as param here this i am unable to solve this in front end i wrote like

 <mat-paginator [pageSize]="10" [length]="totalLength"  [pageSizeOptions]="[5, 10, 25, 100]" (page)="PageEvents($event)"></mat-paginator>


PageEvents(event: PageEvent){
    this.pageNumber = 1;
    const pageSize = +event.pageSize; 
    const currentPage = +event.pageIndex + 1; 
    const pagination = {
      searchQuery: '',
      pageSize: pageSize,
      token: ''
    };
    if(currentPage > this.pageNumber) {

     

      console.log('next button',pageSize,currentPage)
    } else {
     
      console.log('prev button',pageSize,currentPage)

    }

  }

totalLength= 50

here my issues

  1. Although i am sending totallenght ui disabling my prev and next button
  2. How can i achieve this pagination在此处输入图像描述
<mat-paginator
      [length]="total"
      [pageSize]="pageSize"
      [pageSizeOptions]="pageSizeOptions"
      [showFirstLastButtons]="isShowFirstLastBtn"
      (page)="onChangePage($event)"
    ></mat-paginator>

Then in your component file, you can receive the page event as:

 private subscription = new Subscription();
   ngOnInIt() {
      // subscribe to the service for page data
      this.subscription = this.service.tableDataAction$.subscribe(resp => do initial table render);

}

    onChangePage(event: PageEvent) {
     const pageSize = +event.pageSize; // get the pageSize
     const currentPage = +event.pageIndex + 1; // get the current page
    
     this.service.paginationData(pageSize, currentPage); // call the service
    }

  ngOnDestroy() {
   this.subscription.unsubscribe()
  }

in service:
   

    private paginationSubject = new Subject<{}>();
       tableDataAction$ = this.paginationSubject.asObservable();
        paginationData(pageSize: number, currentPage: number) {
            // get or post whatever you prefer, get is more correct choice
           this.http.get(url + queryParams).subscribe(
             (resp) => this.paginationSubject.next(resp)),
             (err) => catchError // handle error
          }

PS: To get total count of pagination you should also sent the total Count of the data present with the current data so that in pagination you can show item n of total

First of all, It is recommended to avoid using a token for pagination. You can simply use skip and limit . Something that you are currently using is pageSize which works as limit and let us call a new param currentPage as skip. Anyways moving ahead with token, the implementation logic is as below.

Step 1

You will need following member variables for component in which paginator is present.

  defaultPayload = {
    searchParams : "",
    pageSize : 2,
    currentPage : 1,
    token : ""
  };
  totalLength = 0;

the defaultPayload is argument to your service through which new data comes in. You need currentPage at angular service level for tokenMap implementation will explain in sometime. totalLength as you have already binded it to mat-paginator.

Before moving ahead, you have a question about totalLength . As shown in image your totalLength is 2, As the pageSize is 10, the functionality of next and previous are disabled. It makes sense too. If your response RecordsCount is 50, it will show up if you have set the member variable as the following step demonstrates.

Step 2 On load

Let's say we are subscribed to the api service as below in ngInit

  ngOnInit() {
    this.getDataService(this.defaultPayload)
    .subscribe(
        res => {
          this.defaultPayload.token = paging['token'];
          this.totalLength = paging['RecordsCount'];
        },
        err => {}
    );
  }

On response, we are:

  • setting default token for first api onload
  • setting response RecordsCount in totalLength (which you might be expecting 50, but its 2)
  • Every time an event occurs in step 3, we will set the data on response here itself.

Step 3 On event

PageEvents(event){
    console.log("event", event, this.defaultPayload);
    const pageSize = event.pageSize; 
    const currentPage = event.pageIndex + 1; 
    this.defaultPayload.pageSize = pageSize;
    this.defaultPayload.currentPage = currentPage;
    this.getDataService(this.defaultPayload)
}

Note We are just resetting our request payload again as per new event and make a service call.

Step 4 Service

let say we have some service as follows that is responsible for providing data. We need to maintain some kind of storage for token. you might use localstorage or simply an object as below whatever suits your need. This is needed because we need to maintain tokens for all (old) prev and (new) next page events.

 constructor() { 
        this.tokenMap = {};
    }
  
    getDataService({...options, currentPage}){
        options.token = findToken(currentPage)
        //http request using {options}
        //on response setToken
        this.setTokenMap(options.currentPage, response['token])
        return responseData
    }

    findToken(page){
        return this.tokenMap[page || 1] || "";
    }

    setTokenMap(page, token){
        this.tokenMap[page] = token;
    }

This service will find the token while making an api call, and also set the new token as per currentPage, hence you don't have to bother about token in component. This will separate your concerns of the token logic and component paginator data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM