Angular MatPaginator not working

前端 未结 30 1546
情歌与酒
情歌与酒 2020-12-04 23:05

I have 2 components. Both have mat-table and paginators and pagination is working for one component and not working for the other component though the code is similar. Below

相关标签:
30条回答
  • 2020-12-04 23:48

    This took me hours to finally track down and understand why my table wasn't working. Placing some console.logs() helped me figure out the order of events and why it didn't work consistently. My scenario was similar to the original issue above with a dynamic data source, but slightly different. For me, when I would first refresh my angular app, the paginator state would be set and then the data for my table would be set. When these events would happen in the this order the paginator worked just as expected.

    Because I was using ReplaySubjects for getting the data for my tables, my paginator state would be set in ngAfterViewInit and then the table data would come in from my subscription (it depends on user ID so I don't have an initial value and that is why I didn't use BehaviorSubjects). My problem was that, when I would navigate to another component in my app, and return to my dynamic table data source, the table data would be set before the paginator state. This would make the paginator show page x, but the displayed data would always be the first page of data.

    To fix this annoying issue I:

    1. Wrote a simple function for setting my table data as someone mentioned above:
      setTableData() {
        // set table data
        this.tableData.data = this.images.filter(img => this.filterData(img));
    
        // some other code below
        ....
      }
    
    1. Added two flags in my component, one for if I had loaded the table data and one for if my pagination state had been set. This way I could ensure that the pagination state is set before the data.
      // initialize our data source for our table and set flags for state
      tableData = new MatTableDataSource<IImage>(this.images);
      loading = true;
      setPageState = false;
    
    1. Added a setTimeout to ngAfterViewInit which would set my paginator state and set my table data only if the table data came through before ngAfterViewInit was called. The setTimeout prevents the annoying "expression changed after value was checked" error.
      ngAfterViewInit() {
        // add pagination state to our table
        setTimeout(() => {
          console.log('Set paginator state');
          this.setPageState = true;
          this.paginator.pageIndex = this.state.pageIndex;
    
          // check if we are not loading data, meaning the table came in first so
          // we need to set the data here
          if (!this.loading) {
            this.setTableData();
          }
        }, 0);
      }
    
    1. Lastly, in ngOnInit, where I subscribe to my data, I do not set my table data unless the paginator state was set first:
      ngOnInit() {
        console.log('ngOnInit');
        this.tableData.sort = this.sort;
        this.tableData.paginator = this.paginator;
    
        // listen for data
        this.dbService.images.subscribe(images => {
          console.log('Data subscription');
          // save images
          this.images = images;
    
          // only set table data if paginator state has been set, otherwise it doesnt work
          if (this.setPageState) {
            this.setTableData();
          }
    
          // hide spinner and update that we have data
          this.loading = false;
        });
    
        // other code
        .....
      }
    

    And with that, my pagination was finally working consistently for when I first login to the app and when I navigate to other pages and go back to my dynamic table.

    0 讨论(0)
  • 2020-12-04 23:49

    I also had this problem. I added reference scheduledOrdersPaginator into pagintaor tag and received with @ViewChild. It solved my pagination problem. Below code may help others.

    dataSource = new MatTableDataSource();
    displayedColumns = ['col1', 'col2', ... ];
    @ViewChild('scheduledOrdersPaginator') paginator: MatPaginator;
    @ViewChild(MatSort) sort: MatSort;
    ngOnInit(): void {
        // Load data
        this.dataSource = new MatTableDataSource(somearray);
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;
    }
    

    html:

    <mat-paginator #scheduledOrdersPaginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons> </mat-paginator> 
    
    0 讨论(0)
  • 2020-12-04 23:50

    I had the same issue (table data displaying but MatPaginator is not working). In my case, I forgot to create "new MatTableDataSource"

    this.dataSource = somearray;
    

    not enable MatPaginator while this.dataSource = new MatTableDataSource(somearray); does.

    extract from material documentation

    "To simplify the use case of having a table that can sort, paginate, and filter an array of data, the Angular Material library comes with a MatTableDataSource that has already implemented the logic of determining what rows should be rendered according to the current table state."

    hope this answer helps someone.

    0 讨论(0)
  • 2020-12-04 23:52

    Angular 7+ (8/9) There is another elegant solution to solve that problem.

    Short Version

    Immediately after setting data source invoke ChangeDetectorRef.detectChanges().

    Long Version

    Step1:

    Import ChangeDetectorRef & Material related stuff

    import { ..., ChangeDetectorRef } from '@angular/core';
    import { MatSort, MatTableDataSource, MatPaginator } from '@angular/material';
    

    Step2:

    Set class-properties in your component

    @ViewChild(MatSort) sort: MatSort;
    @ViewChild(MatPaginator) paginator: MatPaginator;
    

    Step3:

    Inject ChangeDetectorRef in your constructor

    constructor (..., private cdr: ChangeDetectorRef, ...) { ... }
    

    Step4:

    Set data source and invoke detectChanges()

    this.dataSource = new MatTableDataSource (MY_DATA);
    this.cdr.detectChanges();
    

    Optional Steps:

    After that, you can set other properties like

    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
    
    0 讨论(0)
  • 2020-12-04 23:53

    In my case, data coming from service asynchronously so neither could use ngOnInit or ngAfterViewInit, I used ngOnChanges, something like below:

    ngOnChanges(change: SimpleChanges) {
        if (change.properties) {
          if (this.properties.length > 0) {
            this.dataSource = new MatTableDataSource(this.properties);
            this.dataSource.paginator = this.paginator;
          }
        }
      }

    Be sure to set the [DataSource] attribute at mat-table element at html to the data source property from the component so to ensure the data source get bind with the table and paginator.

    0 讨论(0)
  • 2020-12-04 23:56

    None of the above solution worked for me.

    I figured out what was the issue, mainly this.paginator will be undefined until the table is loaded and in view, that's why in some of the in places setTimeout solution works.

    But in my case, my table was hidden behind some ngIf logic so the the table was only loaded after the ngIf becomes true(which happens on user interaction ) , but I was setting this.dataSource.paginator = this.paginator on ngOnInit

    So, the solution depends on your case, the ground truth is make sure the table is loaded only then this.dataSource.paginator = this.paginator

    I resolved it by, when user does the interaction and ngIf becomes true after that I call a function to set the paginator

         initPaginator(){
            this.dataSource.paginator = this.paginator
    }
    
    0 讨论(0)
提交回复
热议问题