-1

Because of the big amount of data with above 30k entries i decided to create a mat table with paginaton. So its working fine right now with my filter, the only problem i have is that only the first page is showing entries and the page navigation is not working. So if i click on next page, the next page is empty

This is my paginator:

  this.persons = data; 
  this.personsFiltered = new MatTableDataSource(this.persons);
  this.personsFiltered.paginator = this.paginator;

FilterChanged(){ //this filter works with a input field to search for a special name
    this.personsFiltered = of(this.persons).pipe(
      //Name
      map( p => (!this.vornameFilter || this.vornameFilter.trim() === '') ? p: p.filter((i: any) => i.vorname?.toLowerCase().includes(this.vornameFilter.toLowerCase()))),
      
     map(p => p.slice(this.paginator?.pageIndex * this.paginator?.pageSize, this.paginator?.pageSize)) 
    )
  }

My Table:

<table mat-table [dataSource]="personsFiltered" *ngIf="personsFiltered">

<ng-container matColumnDef="Name">  
                    <th mat-header-cell *matHeaderCellDef  > Name </th>
                    
                    <td mat-cell *matCellDef="let user"> 
                        {{user.nachname}}, {{user.vorname}}
                    </td>  
                    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>  
                    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator (click)="FilterChanged()" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>  

Why is it not showing also entries on the other pages?

Chopper
  • 47
  • 1
  • 9

2 Answers2

1
  1. You missed length and pageSize options, provide them to mat-paginator and it should help:
<mat-paginator [length]="personsFiltered.data.length" [pageSize]="5" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
  1. You also need to fix your pagination in filtering function - details below.

2a. First way to fix your pagination is by removing this part from your function (map(p => p.slice(this.paginator?.pageIndex * this.paginator?.pageSize, this.paginator?.pageSize)) ) and applying MatTableDataSoruce - this is what I definitely recommend as it makes things much easier, also it makes it easier to add sorting if you need and to combine this sorting with filtering. Good example of it is in Angular Material's doc (https://v5.material.angular.io/components/table/examples - Table with pagination) and their Stackblitz example for it is here: https://stackblitz.com/angular/kbxroarjbeb

You can also look at example provided here: https://stackoverflow.com/a/50269705/14556461

In this approach pagination is done automatically by mat-paginator and your custom code removes data that should be presented on next pages - paginator couldn't load more data as the data would be removed by this function.

2b. Another approach is to do pagination more manually - you can use page event from mat-paginator, something like this:

<mat-paginator
  [length]="length"
  [pageSize]="pageSize"
  [pageSizeOptions]="pageSizeOptions"
  (page)="changePage($event)"
>
</mat-paginator>

and then in your component:

changePage(pageEvent: PageEvent) {
  const startIndex = pageEvent.pageIndex * pageEvent.pageSize;
  const endIndex = startIndex + pageEvent.pageSize;
  this.personsFilteredForCurrentPage = this.personsFiltered.slice(startIndex, endIndex);
}

and in HTML just display personsFilteredForCurrentPage in your mat-table instead of personsFiltered. Update personsFiltered whenever your filters are updated. This way pagination is separated from filtering so you don't have to filter all items each time you switch the page.

Invoke FilterChanged() when you change filters in the table. You need also to handle what happens when you change your filter/filters - as data is changed, you also need to update personsFilteredForCurrentPage after filters change to refresh data in the table.

Btw. This (click)="FilterChanged()" looks quite weird in this place - are you sure it should be here? It seems like this function should be rather invoked on some button's click or on input's change. Anyway I would avoid invoking it when you click on paginator.

  • Thx for your idea! The length option let my table explode, so i only use pageSize and PageSizeOptions :D Also i removed the map line in my filter. Now because i removed it it loads all of my data and not only 5 elements. – Chopper Sep 28 '21 at 10:30
  • 1
    I updated my answer, now it should be more clear what I meant because previous version couldn't be clear enough and could be misleading for you. Please check my updated answer and let me know if it helps. – Pawel Woroniecki Sep 28 '21 at 12:00
  • Okay now i included the personFilteredForCurrentPage system. At least i got one problem. In my FitlerChanged() function im trying to give the filtered Persons with this.personsFilteredForCurrentPage = this.personsFiltered, to my new variable. So personsFilteredForCurrentPage is my new datasource. But now my filter dont work anymore. and i cant filter any names – Chopper Sep 28 '21 at 12:44
  • 1
    Ok, so try to make personsFilteredForCurrentPage an Observable so similarly as you had previously. This should trigger data refresh in the table and should make your filtering working back. Alternatively use DataSource (e.g. MatTableDataSource) which handles data refreshes automatically (you just update data in the dataSource like `this.dataSource.data = newData` and it is refeshed in the table) – Pawel Woroniecki Sep 28 '21 at 14:05
  • Mhm i tried now a few different ways. In a lot of the ways hes loading the data but ignoring the paginator. So he loads all 30k entries on one site. In the case with making personsFilteredForCurrentPage to a MatDataTableSource im getting the Error "ERROR TypeError: fn is not a function" at the beginning of my filter "(this.personsFiltered = of(this.persons).pipe(". It seems that there needs to be a "standard" slice because of the amount of informations. – Chopper Sep 29 '21 at 07:03
  • 1
    Have you tried with less amount of data? The error you observe shouldn't be related to amount of data. Would it be possible to create stackblitz with your code where you're observing this issue? It would be much easier to help you this way. – Pawel Woroniecki Sep 29 '21 at 16:59
  • Stackblitz would be not the same because of my amount of data. In a few days a friend of me will check my code, i will post the answer then here. – Chopper Oct 01 '21 at 05:52
  • 1
    You can always produce bigger amount of data on stackblitz artificially if you want (e.g. prepare function that generates this amount of data). It's unfortunately impossible to help without the knowledge of exact code but I hope you will be able to handle this with your friend. If not - please try to create stackblitz and generate the data artifically there. Also make sure it is really caused by the amount of data (i.e. try to reduce amount of data for testing purposes and check if everything works correctly). More data should only make code slower, not broken. – Pawel Woroniecki Oct 01 '21 at 06:52
  • Alright i will hit you up if i got something new about this. Ty for your help – Chopper Oct 01 '21 at 07:02
  • No problem, good luck with the solution! – Pawel Woroniecki Oct 01 '21 at 07:36
0

So finally we found a solution. It was much more complicated then we thought right here. We created a count method right into the backend controller like this:

 [HttpGet("get/count")]
 public int GetPersonensCount()
 {
      return _context.Personens.Count();
 }
And also we handled the count method into my service and subscription like this:

getPersonDetails(start: number = 0): Observable<PersonenSharing[]>{
    return this.http.get<PersonenSharing[]>(this.pController + start);
  }
  
  

getData(){
      this.pService.getPersonCount().pipe(
        tap(count => {
          for(let i = 0; i < count; i+=100){
            this.pService.getPersonDetails(i).subscribe(data => {
              if(!this.persons){
                this.persons = [];
                this.personsFiltered = new MatTableDataSource(this.persons);
                this.personsFiltered.paginator = this.paginator;
              }
              this.persons = this.persons.concat(data);
              this.FilterChanged();
              if(this.persons.length == count){
                this.loaded = true;
              }
            })
          }
        })
      ).subscribe();

Thats finally how it works, only problem is currently the performance.

Chopper
  • 47
  • 1
  • 9