简体   繁体   中英

Angular 5 Material Paginator resets to negative values when updating pageIndex

I'm using an Angular Material data table to display a list of objects that can be added to. When an object is added to the data source, the page index breaks and shows a negative. The only way I've found to fix this is to reset the page index of the material paginator to 0. However, any further changes to the paginator result in a pageIndex of -1 or a broken paginator. Here is an example:

I first set new data in the Angular Material data source like so:

private refreshTable() {
    // first we update the length of the paginator with the new length of the datasource data to ensure parity
    this.paginator.length = this.dataSource.data.length;


    // next we get the current page number so we can return to it later.
    let currentPage = this.paginator.pageIndex;

    this.tempSubscription2 = this.rrService.getSearchResults(this.searchEnv.outputPayload(true, true)).subscribe(
        (data: any) => {
            this.extractSBRs(data);
            this.dataSource.data = [];
            // Here is where the dataSource is reset...
            this.dataSource.data = this.sbrs;

            this.paginator.length = this.dataSource.data.length;
            this.paginator.pageIndex = 0;
            this.dataSource.paginator = this.paginator;
            console.log('made it this far');

            if (this.dataSource.paginator.pageIndex < currentPage) {
                console.log('need to return to the current page');
                this.paginator.pageIndex = currentPage;
                this.paginator._pageIndex = currentPage;
                this.dataSource.paginator.pageIndex = currentPage;
                this.dataSource.paginator._pageIndex = currentPage;

            }
        },
        (err: any) => {
        },
        () => {
        }
    );
}

When this code is run, updates from the first page are fine because the this.paginator.pageIndex is being set to 0. Once an element is added on a page greater than zero, the table shows the first page, the paginator has a pageIndex of -1 and the paginator in the UI looks like this:

在此输入图像描述

Notice the negative index -9 - 0 . There seem to be very few examples of updating an Angular Material Data Table and even fewer that have further notes about how updating them effects the Angular Material paginator. How can I get the paginator to go to a pageIndex other than 0 without getting the negative index issue?

I've tried updating just the this.paginator which is grabbed via ViewChild() per the recommendation here . I've also tried updating the dataSource.paginator which you can see in the code above.

Here are my imports:

import {
AfterContentInit, AfterViewInit, ApplicationRef, ChangeDetectorRef, 
Component, OnDestroy, OnInit,
    ViewChild
} from '@angular/core';
import { SearchEnvironment } from "../classes/search-environment";
import { SearchFilterDropdown } from "../classes/search-filter-dropdown";
import { ActivatedRoute, Router } from "@angular/router";
import {MatTableDataSource, MatPaginator, MatDialog, MatTable, MatSnackBar} from "@angular/material";
import { RemoteRetrievalService } from "../core/services/remote-retrieval.service";
import { Observable } from "rxjs/Observable";

How can I get the desired paginator behavior of returning to the currentPage index without causing a negative index in the paginator.pageIndex value or the bad user experience of the negative values in the item(s) range?

It is strange how they build some of these components. I am not sure my solution will work, but based upon what I've read in the issue it seems that they can not handle both a length change and pageIndex change in the same digest cycle.

So I would recommend changing the length first, and then later changing the pageIndex .

 this.paginator.length = this.dataSource.data.length;
 this.paginator.pageIndex = 0;
 this.dataSource.paginator = this.paginator;
 console.log('made it this far');

The above sets the values we know will work on the component, and the next part uses window.setTimeout to run the next set of changes after the component has had a chance to update itself.

 if (this.dataSource.paginator.pageIndex < currentPage) {
     window.setTimeout(()=>{
         this.zone.run(()=>{
            console.log('need to return to the current page');
            this.paginator.pageIndex = currentPage;
            this.paginator._pageIndex = currentPage;
            this.dataSource.paginator.pageIndex = currentPage;
            this.dataSource.paginator._pageIndex = currentPage;
            // EDIT: You must then set the datasource paginator back to the newly edited paginator. 
            this.dataSource.paginator = this.paginator;
         });
     });
 }

You will need to inject NgZone to run the code inside Angular's zones (which is for error handling). It's just a good practice when using window.setTimeout .

Keep in mind that window doesn't exist in Angular Universal incase you want to later to do server side rendering, but that's a different issue.

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