Reputation: 544
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
Reputation: 3842
Problem 1
Your search logic is as follows:
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
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