3

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

11
  • What is the value of "event.srcElement.value" or the console.log output? Commented Sep 18, 2020 at 8:16
  • @kvetis is the input user types in search-bar i.e. tom Commented Sep 18, 2020 at 8:17
  • It doesn't make sense to have if (event != '') in one place and event.srcElement.value in another. Also, event will never be '' or any string and thus showlist will always be true Commented Sep 18, 2020 at 8:18
  • can you please show the console output of this line: console.log('count: ', event.srcElement.value, this.students.length) ? Commented Sep 18, 2020 at 8:19
  • 1
    Well, it seems you must be trying to determine if the input was an empty string. But you are treating it as a different type in other places... that can't be right since you don't reassign it. I would do const value = event.target.value; if (value) {}. Use value everywhere else as well instead of event.srcElement.value Commented Sep 18, 2020 at 8:22

2 Answers 2

3

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>
Sign up to request clarification or add additional context in comments.

5 Comments

thank you so much, is there any chance to implement Michael D idea into this as well?
Yeah, he catches an important issue.
also the bug i mentioned in his answer i catch it in your solution as well
const value = event.target.value; if (value) { this.studentsFiltered = this.students.filter((v) => {......
I think if not use this.matchingStudents = this.students; in else part is better so students will have no effect on matchingStudents while it couldn't find results therefore it will not show anything in view
3

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>

5 Comments

thanks, this is good but the problem is no matter what i type i always get some results even if those typed letters are not include any of students names.
I've combined your both answers and it works like charm :)
const value = event.target.value; if (value) { this.studentsFiltered = this.students.filter((v) => {....
I didn't test it. Nice that @AluanHaddad's answer solved the issue :)
@MichaelD well, you solved a big part of it as well. +1

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.