marshall legend
marshall legend

Reputation: 544

Ionic4: searchbar results not working as expected

I am using ion-searchbar in my app. I use the searchbar to filter a list of customers by first name and/or last name, but I am really struggling with these two issues:

Issue 1: The search bar only matches first name OR last name, but not both at the same time. For example: If I am a customer and my name is Marshall Legend and I type in Marshall the filter will work OR if I type in Legend the filter will work, but if i type in Marshall Legend I get no matches.

Issue 2: This is easier to explain as a scenario. The customers list is correctly filtering the list and showing the correct results, such as only people named "Marshall" are showing when I've typed "Marshall" into the searchbar. However, then a new customer is added to the list (from another client) and all of a sudden all customers are being displayed and the filter is ignored, even though "Marshall" is still in my searchbar.

I've been struggling with these two issues for an embarrassing amount of time and would greatly appreciate any help. Below is my code:

My component code

export class Tab2Page implements OnInit {
  public searchTerm: string = "";
  public customerCollection: AngularFirestoreCollection<any>;
  public customers: any[];
  public unfilteredCustomers: any[];

  constructor(private afs: AngularFirestore, 
    public modalController: ModalController,
    private databaseService: DatabaseService) {}

  ngOnInit(){
    this.customerCollection = this.afs.collection('Customers');
    this.customerCollection.valueChanges().subscribe( val => {
      this.customers = val;
      this.unfilteredCustomers = val;
    });
  }

  /**
   * Search functionality 
   */
  public onSearchTerm() {
    if(/\S/.test(this.searchTerm)){
      this.customers = this.unfilteredCustomers.filter(customer => {
        return customer.lastName.toLowerCase().includes(this.searchTerm.toLowerCase())  
        || customer.firstName.toLowerCase().includes(this.searchTerm.toLowerCase());
      });
    } else {
      this.customers = this.unfilteredCustomers;
    }
  }

My template code

    <ion-item-sliding *ngFor="let customer of customers">
          <ion-item-options side="start">
            <ion-item-option (click)="viewCustomerDetails(customer)">Details</ion-item-option>
          </ion-item-options>
        <ion-item>
         <ion-label>
         <ion-icon name="person"></ion-icon> {{customer?.firstName}} 
           {{customer?.lastName}}
         </ion-label>
         </ion-item>
          <ion-item-options side="end">
            <ion-item-option color="danger" (click)="removeCustomer(customer)">Return</ion-item-option>
          </ion-item-options>
    </ion-item-sliding>

Upvotes: 0

Views: 144

Answers (2)

Brian Burton
Brian Burton

Reputation: 3842

Problem 1

Your search logic is as follows:

  1. If first name or last name equals "legend", return true
  2. If first name or last name equals "marshall", return true
  3. If first name or last name equals "marshall legend", return true

Since the first name and last names are split up between two properties in Firestore, the third scenario will never happen. Try this instead:

  public onSearchTerm() {
    if (searchTerms.length < 1) {
      this.customers = this.unfilteredCustomers;
      return;
    }

    const searchTerms = this.searchTerm.split(' ').map(s => s.trim().toLowerCase());

    this.customers = this.unfilteredCustomers.filter(customer => {
      var firstName = customer.firstName.toLowerCase();
      var lastName = customer.lastName.toLowerCase();

      var results = searchTerms.filter(name => firstName.includes(name) || lastName.includes(name));

      return results.length > 0;
    });

  }

Problem 2

In your ngOnInit function you're subscribed to your customers collection watching for any changes, and when that happens it overwrites your this.customers variable. That's why your list refreshes showing all results. Try this instead:

  ngOnInit(){
    this.customerCollection = this.afs.collection('Customers');
    this.customerCollection.valueChanges().subscribe( val => {
      this.unfilteredCustomers = val;

      // If there is a search term, filter the results
      if (this.searchTerm.trim().length > 0) {
        this.onSearchTerm();
      } else {
        this.customers = val;   
      }
    });
  }

Upvotes: 2

Praveen Patel
Praveen Patel

Reputation: 347

You can use like this

public onSearchTerm() {
if(/\S/.test(this.searchTerm)){
  this.customers = this.unfilteredCustomers.filter(customer => {
    let fullname = customer.firstName+" "+customer.lastName
    return fullname.toLowerCase().includes(this.searchTerm.toLowerCase())  ;
  });
} else {
  this.customers = this.unfilteredCustomers;
}

}

This will return either matching firstname or lastname not both

return customer.lastName.toLowerCase().includes(this.searchTerm.toLowerCase())  
    || customer.firstName.toLowerCase().includes(this.searchTerm.toLowerCase());

Upvotes: -1

Related Questions