I have a list of users (at the moment about 450) which I filter using a onValueChanges subscription and javascript filter method. It seems pretty slow. I believe it should be quicker but am unsure if it is the actual filtering of the object or the rerendering the html that is slow.
When I recreated it in stackBlitz it is super fast so am not sure why it is slow to show the filtered items in my project.
The actual object is little different but not by much
address: null emailAddress: "fred.bloggs@example.com" employeeId: 1 extraPhoneNumber: null fullName: "Administrator Account" jobTitle: "Learning Administrator" personId: 52 phoneNumber: "01234567890" photograph: null searchTerms: "Administrator Account, 1, Learning Administrator" totalAlerts: 0 totalCompleted: 0 totalMandatory: 0 totalOverdue: 0 totalToDo: 0
My Html
<form class="" [formGroup]="myForm"> <input type="text" class="input learningItemsSearch" placeholder="Search My Team" name="searchString" formControlName="searchString" /> </form> <cdk-virtual-scroll-viewport itemSize="70" class="viewport"> <div *ngFor="let user of filteredUsers"> <table> <tbody> <tr> <td colspan="3"> {{ user.fullName }} </td> <td colspan="3"> {{ user.jobTitle }} </td> <td colspan="3"> {{ user.emailAddress }} </td> <td colspan="3"> {{ user.phoneNumber }} </td> </tr> </tbody> </table> </div> </cdk-virtual-scroll-viewport>
My Component
this.myForm.valueChanges.pipe( debounceTime(400), distinctUntilChanged(), tap((value: any) => { let searchTerm = value.searchString; this.filteredUsers = this.users.filter((userName) => userName.searchTerms .toLowerCase() .indexOf(searchTerm.toLowerCase()) !== -1) }) ).subscribe( );
Is this the most efficient way to filter an array of objects? Is there another reason why it appears to take some time to display on the screen? There is nothing too complicated in the html. I am using a cdk-virtual-scroll to see if it would load quicker but it is slow without it too.
EDIT: I forgot to use *cdkVirtualFor instead of *ngFor. It is a lot quicker now. I think adding the trackby mentioned below has also helped.
Advertisement
Answer
You may see a rendering speedup by using the trackBy
feature https://angular.io/api/core/TrackByFunction. Add the following function to your component:
public trackById = (_: number, item: any) => item.id; // or userId, whatever is the unique identifier
Then modify your template:
<div *cdkVirtualFor="let user of filteredUsers; trackBy:trackById">