Reputation: 709
I want to make a search bar which will search 'title' from the table below, irrespective of the order of the words in that sentence.
I tried implementing a filter pipe which checks if the search string is present in the title. I also tried splitting both strings in the array and looping through one to check common fields.
Basically, I want the same results on both 'Samsung Metro' and 'Metro Samsung'
Below is the link to the GIF of the working product and issue.
https://user-images.githubusercontent.com/26569942/56949597-f8f6f280-6b50-11e9-8521-bfd1235126d9.gif
Thanks for the help.
///////////////////////
//home.component.html//
///////////////////////
<div class="form-group">
<input type="text" [(ngModel)]="searchTerm">
</div>
<div class="row">
<table class="table table-striped col-12" >
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Price</th>
<th scope="col">Popularity</th>
<th scope="col">Subcategory</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of products | keyvalue | productFilter : searchTerm">
<th scope="row">{{item.value.title}}</th>
<td>{{item.value.price}}</td>
<td>{{item.value.popularity}}</td>
<td>{{item.value.subcategory}}</td>
</tr>
</tbody>
</table>
</div>
/////////////////////
//home.component.ts//
/////////////////////
export class HomeComponent implements OnInit {
jsonData: any;
products: any;
count: number;
searchTerm: string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.getData().subscribe(
(t: any) => {
this.products = t.products;
this.count = t.count;
}
);
}
}
//////////////////////////
//product-filter.pipe.ts//
//////////////////////////
import { PipeTransform, Pipe } from '@angular/core';
@Pipe({
name: 'productFilter'
})
export class ProductFilterPipe {
transform(products: any[], searchTerm: string) {
if (!products || !searchTerm) {
return products;
}
return products.filter(function (product) {
return product.value.title.toLowerCase().includes(searchTerm.toLowerCase());
// Below commented code is my failed try
// product.value.title.toLowerCase().split(" ").filter( item => {
// searchTerm.toLowerCase().split(" ").includes(item);
// })
});
}
}
////////////////////////
//data looks like this//
////////////////////////
{
"count": 3,
"products": {
"6834": {
"subcategory": "mobile",
"title": "Micromax Canvas Spark",
"price": "4999",
"popularity": "51936"
},
"5530": {
"subcategory": "mobile",
"title": "Samsung Galaxy Grand Max",
"price": "12950",
"popularity": "48876"
},
"4340": {
"subcategory": "mobile",
"title": "Apple iPhone 6",
"price": "40999",
"popularity": "46198"
}
}
}
Upvotes: 2
Views: 1558
Reputation: 709
Figured it out something like this.
import { PipeTransform, Pipe } from '@angular/core';
@Pipe({
name: 'productFilter'
})
export class ProductFilterPipe {
transform(products: any[], searchTerm: string) {
if (!products || !searchTerm) {
return products;
}
return ProductFilterPipe.filter(products, searchTerm);
}
static filter(products: Array<{ [key: string]: any }>, searchTerm: string): Array<{ [key: string]: any }> {
return products.filter(function (product: any) {
return searchTerm.trim().toLowerCase().split(" ").some(r=> product.value.title.toLowerCase().indexOf(r) >= 0)
});
}
}
Upvotes: 1
Reputation: 5584
You can create a regular expression from your search string and test it against your data:
new RegExp(['Galaxy', 'Samsung'].map(s => `(?=.*?${s})`).join('') + '.*').test('Samsung Galaxy');
So in your case, split the search term and test product.value.title:
new RegExp(searchTerm.split(' ').map(s => `(?=.*?${s})`).join('') + '.*').test(product.value.title);
Upvotes: 1