1

I have implemented pagination on the server side in one of the endpoints and the response is as shown below. I want to implement pagination in Angular material I have the table already and I want to customize the <mat-paginator> component so that it can accommodate the response. How can I achieve this?

{
    "success": true,
    "msg": "success",
    "data": {
        "count": 1562,
        "total_pages": 16,
        "next": "http://localhost:7000/api/business_list/?page=4",
        "previous": "http://localhost:7000/api/business_list/?page=2",
        "results": [{
            "id": 37,
            "status": 2,
            "date_issued": "2020-09-09",
            "business_name": "Derox corp",
            "business_activity": "electronics",
            "business_id": "190000",
            "calendar_year": 2020,
        }]
    }
}

HTML

<ul class="breadcrumb">
  <li><a routerLink="/liquor/dashboard">DashBoard</a></li>
  <li>Business Permit</li>
  <li>All Businesses</li>
</ul>
<mat-toolbar matTooltip="Shows list of businesses" matTooltipPosition="above">Businesses</mat-toolbar>
<div class="row">
  <div class="col-sm-12">
    <div class="card min-vh-100 ">
      <div class="card-body p-4">
        <!-- <h4 class="card-title">Permits</h4> -->
        <h6 class="card-subtitle">A list of all available liquor businesses recorded int the system</h6>

        <div style="width:100%;">
          <div class="example-button-row">
            <!-- <button class="mat-raised-button btn btn-primary" color="accent"
              matTooltip="Click to add a new license application." (click)="onClickAddPermit()">
              Add
            </button> -->

            <button class="btn btn-success text-white" mat-raised-button
              (click)="exporter.exportTable('xlsx', {fileName:'test', sheet: 'sheet_name', Props: {Author: 'Talha'}})"
              matTooltip="Export data in excel format.">Export</button>

            <div class="row" style="margin:10px;">
              <mat-form-field class="search-form-field" floatLabel="never" matTooltip="search license application.">
                <input matInput [(ngModel)]="searchKey" placeholder="Search" autocomplete="off" (keyup)="applyFilter()">
                <mat-icon matSuffix>search</mat-icon>
                <button mat-button matSuffix mat-icon-button arial-label="Clear" *ngIf="searchKey"
                  (click)="onSearchClear()">
                  <mat-icon>close</mat-icon>
                </button>
              </mat-form-field>

            </div>


          </div>
          <mat-card style="padding-left:40px;padding-right:40px; padding-top:10px">

            <div class="mat-elavation-z8">
              <table class="col-md-12 table table-striped thead-dark" mat-table matTableExporter [dataSource]="listData"
                #exporter="matTableExporter" matSort>

                <ng-container matColumnDef="business_name">
                  <mat-header-cell *matHeaderCellDef mat-sort-header>Business Name</mat-header-cell>
                  <mat-cell *matCellDef="let element" class="truncate-cell"><span class="truncate-text"
                      matTooltip="{{element.business_name}}">{{element.business_name}}</span>
                  </mat-cell>
                </ng-container>

                <ng-container matColumnDef="business_id">
                  <mat-header-cell *matHeaderCellDef mat-sort-header>Business ID. </mat-header-cell>
                  <mat-cell *matCellDef="let element">{{element.business_id}}</mat-cell>
                </ng-container>

                <ng-container matColumnDef="activity_code">
                  <mat-header-cell *matHeaderCellDef>Activity Code. </mat-header-cell>
                  <mat-cell *matCellDef="let element">{{element.activity_code}}</mat-cell>
                </ng-container>

                <ng-container matColumnDef="plot_number">
                  <mat-header-cell *matHeaderCellDef style="justify-content: center;">Plot No. </mat-header-cell>
                  <mat-cell *matCellDef="let element" style="justify-content: center;">{{element.plot_number}}
                  </mat-cell>
                </ng-container>

                <ng-container matColumnDef="ward_name">
                  <mat-header-cell *matHeaderCellDef style="justify-content: center;">Ward</mat-header-cell>
                  <mat-cell *matCellDef="let element" style="justify-content: center;">{{element.ward_name}}

                    <p *ngIf="element.ward_name ==null">
                      <span style="color:red !important;">please update</span>
                    </p>

                  </mat-cell>
                </ng-container>

                <ng-container matColumnDef="sub_county_name">
                  <mat-header-cell *matHeaderCellDef style="justify-content: center;">Sub County</mat-header-cell>
                  <mat-cell *matCellDef="let element" style="justify-content: center;">{{element.sub_county_name}}
                    <!-- <mat-chip *ngIf="element.sub_county_name ==null" color="warn">One fish</mat-chip> -->
                    <p *ngIf="element.sub_county_name ==null">
                      <span style="color:red !important;">please update</span>
                    </p>

                  </mat-cell>
                </ng-container>


                <ng-container matColumnDef="Actions">
                  <mat-header-cell *matHeaderCellDef>Actions</mat-header-cell>
                  <mat-cell *matCellDef="let row">
                    <button mat-icon-button matTooltip="View Permit." (click)="viewPermit(row)">
                      <mat-icon>visibility</mat-icon>
                    </button>
                    <button mat-icon-button mat-icon-button matTooltip="Edit Permit." (click)="editPermit(row)">
                      <mat-icon>create</mat-icon>
                    </button>
                  </mat-cell>
                </ng-container>


                <ng-container matColumnDef="loading">
                  <mat-footer-cell *matFooterCellDef colspan="6">
                    <ngx-spinner bdColor="rgba(51,51,51,0.8" size="medium" color="#fff" loadingText="Loading..."
                      type="ball-scale-multiple"></ngx-spinner>
                  </mat-footer-cell>
                </ng-container>

                <ng-container matColumnDef="noData">
                  <mat-footer-cell *matFooterCellDef colspan="6">
                    No Data
                  </mat-footer-cell>
                </ng-container>


                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>

                <mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide': listData!=null}"></mat-footer-row>

                <mat-footer-row *matFooterRowDef="['noData']"
                  [ngClass]="{'hide': !(listData!=null && listData.data.length==0)}">
                </mat-footer-row>

              </table>
              <!-- <mat-paginator [pageSizeOptions]="[5,10,25,100]" [pageSize]="5" showFirstLastButtons></mat-paginator> -->
              <mat-paginator 
                [length]="pageLength "
                [pageSize]="pageSize"
                [pageSizeOptions]="pageSizeOptions">
                </mat-paginator>

<!-- 
              <ul class="na-pills">
                <li class="nav-item" *ngFor="let p of pages; let i=index">
                  <a  class="nav-link" (click)="setPage(i,$event)">{{i}}</a>
                </li>
              </ul> -->
            </div>
          </mat-card>

        </div>

      </div>
    </div>
  </div>

</div>

TS file

export class PermitListComponent implements OnInit {

  page: number;

  pages: Array<number>;

  listData: MatTableDataSource<any>;

  displayedColumns: string[] = ['business_name',
  'business_id', 'activity_code', 'plot_number', 'ward_name', 'sub_county_name', 'Actions'];


  @ViewChild(MatSort, {static: true}) sort: MatSort;

  @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;

  searchKey: string;

  selectedPermit: any;

  businessId: number;

  pageEvent: PageEvent;

  //var init declaration
  pageLength = 100;
  pageSize = 10;
  pageSizeOptions: number[] = [5, 10, 25, 100];



  constructor(
    private liquorService: LiquorService,
    private dialog: MatDialog,
    private snackbar: MatSnackBar,
    private spinner: NgxSpinnerService,
    private dataService: DataService) { 
      this.liquorService.listen().subscribe((m: any) => {
        console.log(m);
        this.getAllPermits();
    });
    }



  ngOnInit() {

    this. getAllPermits();

    /** spinner starts on init **/

    this.spinner.show();
    /** spinner starts afer 5 secs**/
    setTimeout(() => {
      this.spinner.hide();

    }, 5000);
  }

  setPage(i, event: any) {
    this.page = i;
    // event.preventDefault;
    this.getAllPermits();

  }

  getAllPermits() {
    this.page = 1;
    this.liquorService.getAllPermits().subscribe(
      res => {
        this.listData = new MatTableDataSource(res.data.results);
        this.listData.sort = this.sort;

        // this.pages = new Array(res.data.total_pages);

        const sortState: Sort = {active: 'id', direction: 'desc'};
        this.sort.active = sortState.active;
        this.sort.direction = sortState.direction;
        this.sort.sortChange.emit(sortState);

        // this.pages = new Array(res.data.total_pages);

        this.pageLength = res.data.total_pages;

        this.listData.paginator = this.paginator;
      },

      error => {
        console.log(error);
      }
    );
  }


  onSearchClear() {
    this.searchKey = '';
    this.applyFilter();
  }

  applyFilter() {
    // console.log(this.listData)
    this.listData.filter = this.searchKey.trim().toLocaleLowerCase();
  }


  onClickAddPermit() {
    // console.log("hello");
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(AddPermitFormComponent, dialogConfig);

  }

  // closeModal() {
  //   const dialogConfig = new MatDialogConfig();
  //   dialogConfig.disableClose = true;
  //   dialogConfig.autoFocus = true;
  //   dialogConfig.width = '70%';
  //   this.dialog.open(AddPermitFormComponent, dialogConfig);
  // }

  viewPermit(row: any) {
    // this.selectedLicense = row;
    // console.log(this.selectedLicense);
    this.dataService.formData = row;
    this.selectedPermit = row;
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(EditPermitComponent, dialogConfig);
  }


  editPermit(row: any) {
    // this.selectedLicense = row;
    // console.log(this.selectedLicense);
    this.dataService.formData = row;
    this.selectedPermit = row;
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(EditPermitFormComponent, dialogConfig);
  }

  onDelete(id: number) {
    this.businessId = id;
    console.log(id);

    if (confirm('Are You Sure to delete ??')) {

      this.liquorService.deleteIssuedPermit(this.businessId).then(
        res => {
          this.getAllPermits();
          const msg = 'Deleted successfully';
          // res.msg.toString()
          this.snackbar.open(msg, '', {
            duration: 5000,
            verticalPosition: 'top'
          });
          // Swal.fire('Success!', 'De  leted!', 'success');
          // this.requestData = res;
          // console.log(this.requestData.status);

        }
      );

    }

  }

Screenshot

enter image description here

Philip Mutua
  • 6,016
  • 12
  • 41
  • 84
  • Can you please provide an [mcve] so that we can find the best answer for you, a lack of code ultimately does not lead to a good answer and your learning, rather, someone providing the answer for you. – Wojciech Zylinski Mar 07 '20 at 09:50
  • @VoitekZylinski I have added the code, I would like to know how I can map the total pages (from the response payload) with the angular material's `mat-paginator` component. – Philip Mutua Mar 07 '20 at 12:58

2 Answers2

1

I decided not to use mat-paginator to use this html pagination.

HTML

      <ul class="nav nav-pills">
        <li class="nav-item" *ngFor="let p of pages; let i=index">
          <a  class="nav-link" (click)="setPage(i,$event)"  [ngClass]="{'active': i===page}">{{i}}</a>
        </li>
      </ul>

The in the ts file:

Ts file

export class PermitListComponent implements OnInit {

  page = 1;

  pages: Array<number>;

  listData: MatTableDataSource<any>;

  displayedColumns: string[] = ['business_name',
  'business_id', 'activity_code', 'plot_number', 'ward_name', 'sub_county_name', 'Actions'];


  @ViewChild(MatSort, {static: true}) sort: MatSort;

  @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;

  searchKey: string;

  selectedPermit: any;

  businessId: number;

  pageEvent: PageEvent;

  paginatedResp: any;
      

  constructor(
    private liquorService: LiquorService,
    private dialog: MatDialog,
    private snackbar: MatSnackBar,
    private spinner: NgxSpinnerService,
    private dataService: DataService) { 
      this.liquorService.listen().subscribe((m: any) => {
        console.log(m);
        this.getAllPermits();
    });
    }



  ngOnInit() {

    this. getAllPermits();

    /** spinner starts on init **/

    this.spinner.show();
    /** spinner starts afer 5 secs**/
    setTimeout(() => {
      this.spinner.hide();

    }, 5000);
  }

  setPage(i, event: any) {
    this.page = i;
    event.preventDefault;
    this.getAllPermits();

  }

  getAllPermits() {
    // this.page = 1;
    this.liquorService.getAllPermitList(this.page).subscribe(
      res => {
        this.paginatedResp = res;
        this.listData = new MatTableDataSource(this.paginatedResp.data.results);
        this.listData.sort = this.sort;

        this.pages = new Array(this.paginatedResp.data.total_pages);

        const sortState: Sort = {active: 'id', direction: 'desc'};
        this.sort.active = sortState.active;
        this.sort.direction = sortState.direction;
        this.sort.sortChange.emit(sortState);


        this.listData.paginator = this.paginator;
      },

      error => {
        console.log(error);
      }
    );
  }


  onSearchClear() {
    this.searchKey = '';
    this.applyFilter();
  }

  applyFilter() {
    // console.log(this.listData)
    this.listData.filter = this.searchKey.trim().toLocaleLowerCase();
  }


  onClickAddPermit() {
    // console.log("hello");
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(AddPermitFormComponent, dialogConfig);

  }

  // closeModal() {
  //   const dialogConfig = new MatDialogConfig();
  //   dialogConfig.disableClose = true;
  //   dialogConfig.autoFocus = true;
  //   dialogConfig.width = '70%';
  //   this.dialog.open(AddPermitFormComponent, dialogConfig);
  // }

  viewPermit(row: any) {
    // this.selectedLicense = row;
    // console.log(this.selectedLicense);
    this.dataService.formData = row;
    this.selectedPermit = row;
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(EditPermitComponent, dialogConfig);
  }


  editPermit(row: any) {
    // this.selectedLicense = row;
    // console.log(this.selectedLicense);
    this.dataService.formData = row;
    this.selectedPermit = row;
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.width = '70%';
    this.dialog.open(EditPermitFormComponent, dialogConfig);
  }

  onDelete(id: number) {
    this.businessId = id;
    console.log(id);

    if (confirm('Are You Sure to delete ??')) {

      this.liquorService.deleteIssuedPermit(this.businessId).then(
        res => {
          this.getAllPermits();
          const msg = 'Deleted successfully';
          // res.msg.toString()
          this.snackbar.open(msg, '', {
            duration: 5000,
            verticalPosition: 'top'
          });
          // Swal.fire('Success!', 'De  leted!', 'success');
          // this.requestData = res;
          // console.log(this.requestData.status);

        }
      );

    }

  }




}

Then Updated the service file:

Service file

  getAllPermitList(id: number) {
    console.log(id)
    return this.http.get<any>(`${environment.apiUrl}/api/business_list/?page=` + id, {
      headers: this.headers
    });
  }

Output

enter image description here

When I click on the page number I get the data from that page.

Community
  • 1
  • 1
Philip Mutua
  • 6,016
  • 12
  • 41
  • 84
0

You can simply use a public variable and fill it with the value from your response.

  //var init declaration
  length = 100;
  pageSize = 10;
  pageSizeOptions: number[] = [5, 10, 25, 100];

Then use it in your template like this:

<mat-paginator 
           [length]="length"
           [pageSize]="pageSize"
           [pageSizeOptions]="pageSizeOptions"
</mat-paginator>
CodeMonkey
  • 26
  • 7
  • from the response there is `next` and `previous` in the **data** object which allows one to navigate to the next page with some other data, this has not been accounted from your answer. – Philip Mutua Mar 07 '20 at 13:26
  • I'm not sure If I understand your question correctly. But I think you can sort your data Array (e.g. what you should see in the first 50 rows) and in this way you can achieve what data is in which page. Or do you mean that you want to load new data from the backend when you click on the 'Next' button and set the Paginator again? – CodeMonkey Mar 07 '20 at 13:40
  • the data is already paginated from the server side as you can see above from the response. I did so because initially the response was returning everything, you can imagine returning 5000 records at once from the response. I would like it possible for one to click on `next` on the front-end then will be redirected to the next page with data i don't know whether it's possible customizing the mat-paginator. – Philip Mutua Mar 07 '20 at 13:51