[Fixed] Is there an alternative to slice method in angular pagination which retains the full array?

Issue

Here’s what I’m doing:

    <mat-list-item *ngFor="let company of (companies | filter:filterText | slice:lowValue:highValue ); let ix=index;" routerLink="/profile" [queryParams] ="{id: company.id, page:pageIndex}" >
        
        <div mat-list-icon>
            <img width="25" src="{{ getCompanyLogo(company.domain) }}" />
        </div>
        <span fxFlex="10"></span>
        <a mat-line mat-line color="primary">{{ company.name }}</a>
        <p mat-line></p>
        <mat-divider></mat-divider>
    </mat-list-item>

lowValue = pageSize*pageIndex
highValue = lowValue + pageSize

And this works.

However, the problem that I’m facing right now is after I added the filter for filtering data from the array. When I’m on the first page which only shows 10 items, I can search using a keyword in the entire array. But soon as I hit next page, the array gets sliced and a new array with only the items to display is returned. And now, when I search for an item, all it searches for is the new sliced array – so it may not find what I’m searching for and returns empty, even though the item exists in the original array.

What’s the best way to resolve this?

Solution

Don’t use the pipes and instead listen to the events when your filterText / pageIndex changes.

You didn’t show us much of your code, so I’ll run with some assumptions.

I assume all your records are filtered / paged localaly and the companies is the local property holding ALL the companies. You can do something along the lines of:

// Define a new property - and assign initial value of a shallow clone of the initial array.
// Use this property in the ngFor without the pipes.
displayedRecords: Company[] = [...this.companies];

// All the other stuff you already have
...

// New method - hook it up to when filterText OR pageIndex changes
private filterRecords(): void {
    // Apply filter logic from your custom pipe - below is an example.
    let filtered: Company[];
    
    if (this.filterText !== undefined && this.filterText.length > 0) {
        filtered = this.companies.filter(c => c.name.toLowerCase().includes(this.filterText.toLowerCase()));
    } else {
        filtered = [...this.companies];
    }
    
    const lowValue = this.pageSize * this.pageIndex
    const highValue = lowValue + this.pageSize

    this.displayedRecords = filtered.slice(lowValue, highValue);
}

Leave a Reply

(*) Required, Your email will not be published