Reputation: 794
I have an array of wines containing objects with data for each wine:
var wines = [
{ _id: '59a740b8aa06e549918b1fda',
wineryName: 'Some Winery',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png' },
{ _id: '59a7410aaa06e549918b1fdb',
wineryName: 'Some Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png' },
{ _id: '59a74125aa06e549918b1fdc',
wineryName: 'Some Winery',
wineName: 'Rose',
wineColor: 'Rose',
imageLink: '/img/FortBerensRose.png' },
{ _id: '59a74159aa06e549918b1fdd',
wineryName: 'Some other Winery',
wineName: 'Rose',
wineColor: 'Rose',
imageLink: '/img/FortBerensRose.png' },
{ _id: '59a7417aaa06e549918b1fde',
wineryName: 'Some other Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png' },
{ _id: '59a8721f4fd43b676a1f5f0d',
wineryName: 'Some other Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png' },
{ _id: '59a872244fd43b676a1f5f0e',
wineryName: 'Winery 3',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png' } ]
I can figure out how to search -- case insensitive -- for a wine object, while specifying which key of the object to search in, like this:
var search = 'Noir'
filteredWines = function () {
return wines.filter(function(wine){
return (wine.wineName.toLowerCase().indexOf(search.toLowerCase())>=0;
});
};
Returns:
[ { _id: '59a740b8aa06e549918b1fda',
wineryName: 'Some Winery',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png' },
{ _id: '59a872244fd43b676a1f5f0e',
wineryName: 'Winery 3',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png' } ]
However, if var search = 'Winery 3'
or var search = 'red'
then it will obviously return no results, as it's looking in the value of wineName
of each object in the array.
So is there a way to use filter (or another method?) to search through all key values, or even better, multiple specified key values and return an array of the matching objects?
Something like:
filteredWines = function () {
return wines.filter(function(wine){
return ((wine.wineName.toLowerCase() && wine.wineName.toLowerCase()
&& wine.wineName.toLowerCase()).indexOf(search.toLowerCase())>=0;
});
};
Or am I completely barking up the wrong tree?
PS. I'm using Vue.js 2 so if there's a better way inside vue then I'm all ears!
Upvotes: 5
Views: 10729
Reputation: 350054
You could have a more generic function that will scan all the properties for the string. Loop through all property values with Object.values()
and use some
to bail out as soon as you have a match:
filteredWines = function (search) {
var lowSearch = search.toLowerCase();
return wines.filter(wine =>
Object.values(wine).some(val =>
String(val).toLowerCase().includes(lowSearch)
)
);
}
If you prefer to pass specific keys to search in:
filteredWines = function (search, keys) {
var lowSearch = search.toLowerCase();
return wines.filter(wine =>
keys.some(key =>
String(wine[key]).toLowerCase().includes(lowSearch)
)
);
}
Call as
filteredWines('Winery 3', ['wineryName', 'wineName']);
Upvotes: 23
Reputation: 13
Used the solution from "trincot" and changed it for my angular5 application to this:
filter(search, list): Observable<IFilteredList> {
return list.filter(item => {
return Object.values(item).some(val =>
String(val).includes(search)
);
})
}
Upvotes: 1
Reputation: 1332
Can also be done this way:
this.wines = this.wines.filter((item) => {
return (item.wineryName.toString().toLowerCase().indexOf(val.toLowerCase()) > -1 ||
item.wineName.toLowerCase().indexOf(val.toLowerCase()) > -1 ||
item.wineColor.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
Upvotes: 1
Reputation: 5000
I also would recommend trying a more general approach:
function getMatchingWhine(keys, searchTerm, wines) {
function extractTextFromKeys(keys, object) {
let text = '';
keys.forEach(key => {
text += ' ' + object[key];
});
return text.toLowerCase();
}
return wines.filter(wine => {
const relevantText = extractTextFromKeys(keys, wine);
return relevantText.includes(searchTerm.toLowerCase());
});
}
Upvotes: 0
Reputation: 3241
Filter works. Oops, I read the question a bit more closely. Filter still works but you have to filter the values, too.
let wines = [
{
_id: '59a740b8aa06e549918b1fda',
wineryName: 'Some Winery',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png'
},
{
_id: '59a7410aaa06e549918b1fdb',
wineryName: 'Some Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png'
},
{
_id: '59a74125aa06e549918b1fdc',
wineryName: 'Some Winery',
wineName: 'Rose',
wineColor: 'Rose',
imageLink: '/img/FortBerensRose.png'
},
{
_id: '59a74159aa06e549918b1fdd',
wineryName: 'Some other Winery',
wineName: 'Rose',
wineColor: 'Rose',
imageLink: '/img/FortBerensRose.png'
},
{
_id: '59a7417aaa06e549918b1fde',
wineryName: 'Some other Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png'
},
{
_id: '59a8721f4fd43b676a1f5f0d',
wineryName: 'Some other Winery',
wineName: 'Pinot Gris',
wineColor: 'White',
imageLink: '/img/FortBerensPG.png'
},
{
_id: '59a872244fd43b676a1f5f0e',
wineryName: 'Winery 3',
wineName: 'Pinot Noir',
wineColor: 'Red',
imageLink: '/img/FortBerensPN.png'
}
];
let search = (val) => wines.filter(w => Object.values(w).filter(v => v.toLowerCase().indexOf(val.toLowerCase()) !== -1).length > 0);
console.log(search('some'));
Upvotes: 0