mafortis
mafortis

Reputation: 7138

Filter array in angular

I have search-bar that I want to filter my array results but it does not return results.

Code

HTML

// search bar
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>

// results
<ion-list *ngIf="showList" class="studentsList">
  <ion-item *ngFor="let student of students">
    {{student.name}}
  </ion-item>
</ion-list>

Component

students: any[] = []; // sample data array provided below
showList: boolean = false;
searchQuery: string = '';

getItems(event) {
  if (event != '') {
    this.students = this.students.filter((v) => {
      return (v.name.toLowerCase().indexOf(event.srcElement.value.toLowerCase()) > -1);
    });
    this.showList = true;
  } else {
    this.showList = false;
  }
  console.log('count: ', event.srcElement.value, this.students.length);
}

Sample data array

{
    "data": [
        {
            "id": 4,
            "name": "Arina",
            "username": "arina",
            "email": "[email protected]",
        },
        {
            "id": 5,
            "name": "Tom",
            "username": "tom",
            "email": "[email protected]",
        }
    ],
    "message": "Students are ready."
}

Any idea?

Update

requested data screenshot

one

Upvotes: 3

Views: 963

Answers (2)

Aluan Haddad
Aluan Haddad

Reputation: 31873

There are a couple of issues in your method

getItems(event) {
  if (event != '') {
    this.students = this.students.filter((v) => {
      return (v.name.toLowerCase().indexOf(event.srcElement.value.toLowerCase()) > -1);
    });
    this.showList = true;
  } else {
    this.showList = false;
  }
  console.log('count: ', event.srcElement.value, this.students.length);
}

Firstly, event is not a string based on what you have passed from your Angular markup, $event, so if (event != '') will always be true.

So we actually want to compare the value of the event, with '' to make sure there is text entered.

We can solve both issues with a minor refactoring as follows

getItems(event: Event) {
  const value = event.target.value;
  if (value !== '') {
    this.students = this.students.filter((v) => {
      return (v.name.toLowerCase().indexOf(value.toLowerCase()) > -1);
    });
    this.showList = true;
  } else {
    this.showList = false;
  }
  console.log('count: ', value, this.students.length);
}

As Micheal D astutely observes, if we assign the filtered students to students property, we will lose the ability to reset any filtering because we won't have the original array.

To resolve this, we need to store the original students in a dedicated property so we can reset our filtered collection back to it. In fact, we should do this when the filter value is emtpty

// original students array.
students: Student[] = [];

// filtered array we iterate over in search results
matchingStudents = [];

getItems(event: Event) {
  const value = event.target.value;
  if (value !== '') {
    this.matchingStudents = this.students.filter((v) => {
      return (v.name.toLowerCase().indexOf(value.toLowerCase()) > -1);
    });
    this.showList = true;
  } else {
    this.showList = false;
  }
  console.log('count: ', value, this.matchingStudents.length);
}

Finally, I'll do some additional cleanup since your filter can be simplified making it simultaneously more readable and concise

getItems(event: Event) {
  const value = (event.target.value || '').toLowerCase();
  this.showList = value !== '';
  if (showList) {
    this.matchingStudents = this.students.filter(v => v.name.toLowerCase().includes(value));
  }
  console.log('count: ', value, this.students.length);
}

Template

// search bar
<ion-searchbar (ionInput)="getItems($event)"></ion-searchbar>

// results
<ion-list *ngIf="showList" class="studentsList">
  <ion-item *ngFor="let student of matchingStudents">
    {{student.name}}
  </ion-item>
</ion-list>

Upvotes: 3

Barremian
Barremian

Reputation: 31125

I see multiple issues.

  1. You're assigning the filtered students back to the this.students variable. So for the next search, the source list isn't available anymore. I'd say you could introduce another variable to hold the filtered students list.

  2. You're checking for an empty event field with condition event != '' whereas it should actually be event.srcElement.value != ''.

Try the following

Controller

studentsFiltered = [];

getItems(event) {
  if (event.srcElement.value != '') {
    this.studentsFiltered = this.students.filter((v) => {
      return (v.name.toLowerCase().indexOf(event.srcElement.value.toLowerCase()) > -1);
    });
    this.showList = true;
  } else {
    this.showList = false;
    this.studentsFiltered = [];
  }
  console.log('count: ', event.srcElement.value, this.studentsFiltered.length);
}

Template

<ion-list *ngIf="showList" class="studentsList">
  <ion-item *ngFor="let student of studentsFiltered">
    {{student.name}}
  </ion-item>
</ion-list>

Upvotes: 3

Related Questions