I am filtering on the cached query result to see if it has the search value.
return this.cachedResults.filter(f => f.name.toLowerCase().indexOf(this.searchValue.toLowerCase()) !== -1);
This works great if the searchvalue is exactly same as the f.name. I want to filter even if it has the partial value. Like a wild card filtering. How can I do that here?
What you're doing will match partially as well in case when f.name includes whole of searchValue doesn't matter at what position.
What you might also want is, it should match even when searchValue includes whole of f.name and not just the other way around.
return this.cachedResults.filter(f => {
return f.name.toLowerCase().indexOf(this.searchValue.toLowerCase()) !== -1)
|| this.searchValue.toLowerCase().indexOf(f.name.toLowerCase()) !== -1)
}
Also consider checking out String.prototype.includes()
Try to use regexp (below support for ? and * wildcards)
let cachedResults = ['abcdef', 'abc', 'xyz', 'adcf', 'abefg' ];
let wild = 'a?c*';
let re = new RegExp('^'+wild.replace(/\*/g,'.*').replace(/\?/g,'.')+'$');
let result = cachedResults.filter( x => re.test(x.toLowerCase()) );
console.log(result);
Related
I will describe the situation for more clarity. I have an array
like this
animalsArray = {
animalID : number,
animalName: string,
animalDescription: string,
animalChild: animalsArray[]
}
Now I have to filter these animals using animalName from user input by textfield. Some animals can have n number of animalChild or non at all or animalChild can have another animalChild inside it.
I already have a code like this
public animalsArray:animalsArray[]
this.filteredanimalsArray.next(
this.animalsArray.filter(item => (item.animalName.toLowerCase().indexOf(search) > -1))
);
To filter the main animalsArray and it works fine but the user input doesn't go through the child arrays.
How can I solve this problem? Thanks in advance
Maybe you could use recursivity like this :
function filterAnimals(animals, name) {
return animals.filter(animal => {
const matching = animal.animalName.toLowerCase() === name.toLowerCase();
const hasChildMatch = Array.isArray(animal.animalChild) && filterAnimals(animal.animalChild, name).length > 0;
return matching || hasChildMatch;
});
}
const search = 'leon';
const filterdAnimals = filterAnimals(animalsArray, search);
So pretty much I have an inputted URL and I am trying to see if it starts with any of the following URLs:
"https://open.spotify.com/playlist/",
"https://www.youtube.com/watch",
"https://youtu.be/",
"https://open.spotify.com/track/",
"https://youtube.com/playlist",
So how it should work is if I were to input "https://open.spotify.com/track/1vrd6UOGamcKNGnSHJQlSt?si=61680eaef0ac419e" it would return that it matched "https://open.spotify.com/track/".
If I were to input "https://youtu.be/5qap5aO4i9A" it would return "https://youtu.be/".
So far I have
url.match(/^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/)
url.match(/^(https?:\/\/)?(www\.)?(m\.)?(youtube\.com|youtu\.?be)\/.+$/gi)
but it's not taking me down the right path and I am extremely lost. Thank you!
Since you need to get the specific prefix that matched, checking with startsWith would probably be simpler than using a regular expression:
const prefixes = [
"https://open.spotify.com/playlist/",
"https://www.youtube.com/watch",
"https://youtu.be/",
"https://open.spotify.com/track/",
"https://youtube.com/playlist",
];
function getPrefix(url) {
const urlLower = url.toLowerCase();
return prefixes.find((prefix) => urlLower.startsWith(prefix));
}
getPrefix("https://open.spotify.com/track/1vrd6UOGamcKNGnSHJQlSt?si=61680eaef0ac419e"); // "https://open.spotify.com/track/"
getPrefix("https://youtu.be/5qap5aO4i9A"); // "https://youtu.be/"
You should not use regex for that purpose you are using. Since you have all the list of urls you have to match against. You just have to check with the url you receive.
const list = ["https://open.spotify.com/playlist/",
"https://www.youtube.com/watch",
"https://youtu.be/",
"https://open.spotify.com/track/",
"https://youtube.com/playlist",
];
function getMeMatchedURL(url) {
const matchedURL = list.filter(item => {
return url.substring(0, item.length) === item;
});
console.log(matchedURL);
}
getMeMatchedURL("https://open.spotify.com/track/1vrd6UOGamcKNGnSHJQlSt?si=61680eaef0ac419e");
getMeMatchedURL("https://youtu.be/5qap5aO4i9A");
From this you will get the url it matches, if it return empty array then it didn't match any of the list.
I have a search function that takes input/query text from a search bar. I want it to work for multiple search terms like "javascript react" or with more or less search terms. The input is saved in an array in state ("query") and compares to an object "workitem" and its property "description".
Let say:
workitem.description.includes(this.state.query)
where
this.state.query // = ["react", "javacript"]
Above will only work for certain situations. I want to see if the array/object includes ANY elements of the state. How to do it?
// if needed, do a
// if (!workitem.description || !this.state.query) {
// return false;
// }
Considering description is an array:
return workitem.description.some(desc => this.state.query.indexOf(desc) >= 0)
Considering description is a string:
return workitem.description
.split(' ')
.some(desc => state.query.indexOf(desc) >= 0);
How about this:
workitem.description.split(' ').some(str => this.state.query.includes(str))
I'm quite new to ReactJS and work on a simple application which shows many different data (called apps). I want to implement a live free text search-filter. For that I'm using an Input Element, calling a JavaScript function if the value is changing. It's working quite good. But only for one string. If I want to filter for more words it's handled as an "AND" filter. But I want an "OR" filter.
I have the apps and filter them with a searchString. The User has to input at least three characters. If the user enters two words with three characters f.e. 'app' and 'red', I want to filter for the elements which has the words 'app' OR 'red' in the title. If min. one of the filter-strings matches, the app is shown. That's the plan.
I tried with .indexOf(), .includes() and nothing matches, even in the documentation I found nothing like an "OR" filter-search.
Here is my code, working for one string:
updateSearch(event) {
let searchString = event.target.value.toLowerCase()
let searchStringSplit = searchString.split(/(\s+)/).filter( function(e) { return e.trim().length >=3; } ); //Only words with at least 3 chars are allowed in the array
if (searchString.length >= 3) { //Check if the minimun amount of characters is fullfilled
let allApps = this.props.applications;
let apps = allApps.filter(app =>
app.title.toLowerCase().includes(searchString)
);
this.props.updateApplications(apps);
} else {
this.clearSearch()
}
}
my Input element:
<Input
id="freeTextSearch"
className="searchInput"
onChange={this.updateSearch.bind(this)}
autoComplete="off"
action={
<Button
id="freeTextSearchButton"
name="search"
icon="search"
onClick={() => this.clearSearch()}
/>
}
placeholder="Search"
/>
Thanks for the help
Yvonne
ANSWER:
Thank you 'Silvio Biasiol'. Your Solution gave me the right hint. Now I have an 'OR' filter-search matching at least one word. The function now looks like:
updateSearch(event) {
let searchString = event.target.value.toLowerCase()
let searchStringSplit = searchString.split(/(\s+)/).filter( function(e) { return e.trim().length >=3; } )
if (searchStringSplit.length >=1) { //Check if there is at least on word with tree letters
let allApps = this.props.applications
// If at least a word is matched return it!
let apps = allApps.filter(app => {
let containsAtLeastOneWord = false
searchStringSplit.forEach(searchWord => {
if (app.title.toLowerCase().includes(searchWord))
containsAtLeastOneWord = true;
})
if (containsAtLeastOneWord)
return app
}
);
this.props.updateApplications(apps)
} else { // user deletes manually every word
this.clearSearch()
}
}
Thanks at everyone
If you just want to match at least one word than it's pretty easy :)
let string = "My cool string"
let possibleStrings = [
'My cool string',
'My super cool string',
'Another',
'I am lon but sadly empty',
'Bruce Willis is better than Pokemon',
'Another but with the word string in it',
'Such string much wow cool']
// Split spaces
let searchString = string.toLowerCase().split(' ')
// Log the result, just wrap it in your react script
console.log(possibleStrings.filter(string => {
let containsAtLeastOneWord = false;
// If at least a word is matched return it!
searchString.forEach(word => {
if (string.toLowerCase().includes(word))
containsAtLeastOneWord = true;
})
if (containsAtLeastOneWord)
return string
}))
You are not using your searchStringSplit array. Using this array you could do the following:
const searchRegex = new RegExp(searchStringSplit.join("|"))
let apps = allApps.filter(app =>
searchRegex.test(app.title.toLowerCase())
);
You join your searchStringSplit array into a regex with the form term1|term2|term3... and match it aginst the title.
Another option would be to use the Array.prototype.some() function like this:
let apps = allApps.filter(app =>
searchStringSplit.some(searchString => app.title.toLowerCase().includes(searchString))
);
You fitler all your apps and for each app you check if it's title includes 'some' of the search strings.
trying to understand your code, suppose that searchString is "facebook twitter youtube"
let searchStringSplit = searchString.split(/(\s+)/).filter( function(e) { return e.trim().length >=3; } );
//searchStringSplit is like [ "facebook", "twitter", "youtube" ]
//allApps is like ["TWITTER","INSTAGRAM"]
allApps.filter(app=> searchStringSplit.includes(app.toLowerCase()))
//returning me all apps in allApps that are includes in searchStringSplit
// so return ["TWITTER"]
not sure if it's exactly what you need...if it's not please let me know so I can change the answer...
I'm having a small issue with React (still new to it). I have an array of Results. These Results have nested Bookings, also in an array, and the latter is what I'm manipulating.
When User creates Booking, everything goes as expected - findIndex gets the correct Result element and modifies its Bookings array accordingly.
However, when I want to "Unbook", it only finds the last Result in the array, and findIndex is always -1 (so I haven't even gotten to the Bookings part, because the Result index I get is wrong).
The code is similar, my items all have unique keys, and I don't understand what could be the problem (using Alt as Flux implementation)?
Here is what happens on Create:
onCreateBookingSuccess(data) {
let resultIndex = this.results.findIndex((result) => result.id === data.id);
this.results.update(resultIndex, (result) => result.bookings.push(data));
toastr.info('Booked! User will receive notification.');
}
And on delete:
onDestroyBookingSuccess(data) {
let resultIndex = this.results.findIndex((result) => result.id === data.id);
var myBooking;
this.results.map((result) => {
myBooking = result.bookings.findIndex((booking) => booking.id === data.booking);
});
this.results.update(resultIndex, (result) => result.bookings.splice(myBooking,1));
toastr.warning('Unbooked! User will receive notification.');
}
My object:
<Result key={result.id} id={result.id} bookings={result.bookings} />
As I mentioned, the first operation goes as planned, everything is modified as it should. The issue with the second op starts from the very beginning, when resultIndex returns -1.
The problem seems to be here:
var myBooking;
this.results.map((result) => {
myBooking = result.bookings.findIndex((booking) => booking.id === data.booking);
});
You’re always assigning to myBooking, even when the index is not found (-1) after having already found it, so it’s equivalent to this.results.last().bookings.findIndex(...). Really you only want to get the (first?) value that’s not -1:
var myBooking = this.results.map((result) => {
myBooking = result.bookings.findIndex((booking) => booking.id === data.booking);
}).find((index) => index != -1);
Also, consider renaming myBooking to better indicate it’s an index and not the actual record.