Use "include" for ANY string in a array - javascript

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))

Related

Can you merge an array of object into just one "big" array?

I need to filter based on a search of words,
When I look up one word it pulls up what I need, but I've been having some trouble when it comes to seaching for multiple words that meet the requirements.
So the thing is, I need to keep the previous search and add into this array the next results from the second word.
/* ===== Search images by keyword =====*/
searchByKeyword() {
if (this.searchText != "" && this.searchText != null) {
if (this?.plansBeforeSearch?.length == 0) {
this.plansBeforeSearch = this.selectedPlans;
}
this.searchTextDivision();
for (let i = 0; i < this.searchTextArray.length; i++) {
/* this.filteredImages = */
this.test[i] = this.planCollection
.filter(
(pl) =>
this.plansBeforeSearch.find((p) => p.name == pl.name) != null
)
.filter((plan: Plan) => {
return [
plan.id,
plan.code,
plan.name,
plan.gallery,
plan.tags,
plan.brand,
plan.description,
plan.width,
plan.depth,
plan.sqf,
plan.bedrooms,
].some((field) =>
field
?.toString()
?.toLowerCase()
?.includes(
this.searchTextArray[i].toString().toLowerCase().trim()
)
);
});
}
this.filteredImages = this.test[0];
console.log(this.test);
console.log(this.filteredImages);
}
}
I created an array of the words I want to use and for each loop I kept them on this test array. It keeps all images that meet the requirement
But when I pass it to the filteredImages array that is the one that displays the images, I can only pass ONE position. So in the code I shared I set up the first position to show, but I need all three of them!
I thought maybe if I merge all the arrays that the test array has into one array with one position only I can pass that to the filteredImages
Try with flat array:
this.filteredImages = this.test.flat()

Trouble with React/JS filter

I am trying to implement a filter function that is able to search in two separate JSON fields when a user types in a search bar. Searching the whole JSON returns errors and if I repeat this function, the two similar functions cancel each other out.
My current filter function:
let filteredOArt = origArt.filter((origAItem) => {
return origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())
});
I want to be able to have the search look within the "authors" field as well as a "description" field.
Before the React render, I have this function listening to the state:
updateSearch(event) {
this.setState({ search: event.target.value })
}
Then my search function is in an input field in the React return:
<h6>Search by author name: <input type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} /></h6>
You can tweak the function a bit like this
let filteredOArt = origArt.filter((origAItem) => {
return (
(origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())||
(origAItem.description.toLowerCase().includes(this.state.search.toLowerCase())
)
)
});
You actually can do a filter for both fields.
Given you have your searchValue and your array with the objects you could filter this way:
const filterByAuthorOrDescription = (searchValue, array) =>
array.filter(
item =>
item.authors.toLowerCase().includes(searchValue.toLowerCase()) ||
item.description.toLowerCase().includes(searchValue.toLowerCase())
);
const filtered = filterByAuthorOrDescription(this.state.search, articles);
filtered will now contain an array of objects that contain your searchValue in either description or authors that you can map through.
You could use some to check if the filter is positive for at least one field :
let filteredOArt = origArt.filter(origAItem => ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase())))
Just iterate over the different field names you want to use.
Some will return true if any of the fields mentioned contains your string and avoid repetitions in your code.
Long syntax :
origArt.filter(origAItem => {
return ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase()))
})

Check location path/search/hash for matching value

I have an array of strings like so: ['foo', 'bar', 'foo/*/test'] and a random URL like this: http://www.example.com/foo/bar?test=123/another=one#test.
The URL may or may not contain a query or a hash prop.
Is there a regex or simple functionality to check the URL, in the URL contains any of those values in the array?
I am aware of the String.prototype.includes function so we could just do:
let path = location.pathname and then path.includes('foo'), but I want strings that contain the structure of foo/*/bar/ to be of higher importance.
For example if the URL is like this: http://www.example.com/foo/1234/test, the function should only return for the value foo/*/test instead of directly return with the foo value inside of the array.
So as soon as I have a string inside of the array which contains a / or something, I want this value to check first or give this the top prio so to speak.
Thanks!
Since the formatting inside a reply is all messed up, I have to post it like this:
#VincentDecaux totally understand.My first thoughts would have been sth like this:
function checkUrl(url, arr) {
const checkForPaths = arr.filter(val => val.match(/[\/](\w+)/ig));
if (checkForPaths.length) {
return true;
}
const filteredArray = arr.filter(val => url.includes(val));
if (filteredArray.length) {
return true;
}
return false;
}
This might already work since I only want the function to return true/false in order to display sth. on the page depemding on this.

Comparing 2 Json Object using javascript or underscore

PS: I have already searched the forums and have seen the relevant posts for this wherein the same post exists but I am not able to resolve my issue with those solutions.
I have 2 json objects
var json1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222", addrs:"def", tab:"tab2"}];
var json2 = [{id:"tab1"},{id:"new"}];
I want to compare both these and check if the id element in json2 is present in json1 by comparing to its tab key. If not then set some boolean to false. ie by comparing id:"tab1" in json2 to tab:"tab1 in json1 .
I tried using below solutions as suggested by various posts:
var o1 = json1;
var o2 = json2;
var set= false;
for (var p in o1) {
if (o1.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
for (var p in o2) {
if (o2.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
Also tried with underscore as:
_.each(json1, function(one) {
_.each(json2, function(two) {
if (one.tab!== two.id) {
set= true;
}
});
});
Both of them fail for some test case or other.
Can anyone tell any other better method or outline the issues above.
Don't call them JSON because they are JavaScript arrays. Read What is JSON.
To solve the problem, you may loop over second array and then in the iteration check if none of the objects in the first array matched the criteria. If so, set the result to true.
const obj1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222",addrs:"def", tab:"tab2"}];
const obj2 = [{id:"tab1"},{id:"new"}];
let result = false;
for (let {id} of obj2) {
if (!obj1.some(i => i.tab === id)) {
result = true;
break;
}
}
console.log(result);
Unfortunately, searching the forums and reading the relevant posts is not going to replace THINKING. Step away from your computer, and write down, on a piece of paper, exactly what the problem is and how you plan to solve it. For example:
Calculate for each object in an array whether some object in another array has a tab property whose value is the same as the first object's id property.
There are many ways to do this. The first way involves using array functions like map (corresponding to the "calculate for each" in the question, and some (corresponding to the "some" in the question). To make it easier, and try to avoid confusing ourselves, we'll do it step by step.
function calculateMatch(obj2) {
return obj2.map(doesSomeElementInObj1Match);
}
That's it. Your program is finished. You don't even need to test it, because it's obviously right.
But wait. How are you supposed to know about these array functions like map and some? By reading the documentation. No one help you with that. You have to do it yourself. You have to do it in advance as part of your learning process. You can't do it at the moment you need it, because you won't know what you don't know!
If it's easier for you to understand, and you're just getting started with functions, you may want to write this as
obj2.map(obj1Element => doesSomeElementInObj1Match(obj1Element))
or, if you're still not up to speed on arrow functions, then
obj2.map(function(obj1Element) { return doesSomeElementInObj1Match(obj1Element); })
The only thing left to do is to write doesSomeElementInObj2Match. For testing purposes, we can make one that always returns true:
function doesSomeElementInObj2Match() { return true; }
But eventually we will have to write it. Remember the part of our English description of the problem that's relevant here:
some object in another array has a tab property whose value is the same as the first object's id property.
When working with JS arrays, for "some" we have the some function. So, following the same top-down approach, we are going to write (assuming we know what the ID is):
In the same way as above, we can write this as
function doesSomeElementInObj2Match(id) {
obj2.some(obj2Element => tabFieldMatches(obj2Element, id))
}
or
obj2.some(function(obj2Element) { return tabFieldMatches(obj2Element, id); })
Here, tabFieldMatches is nothing more than checking to make sure obj2Element.tab and id are identical.
We're almost done! but we still have to write hasMatchingTabField. That's quite easy, it turns out:
function hasMatchingTabField(e2, id) { return e2.tab === id; }
In the following, to save space, we will write e1 for obj1Element and e2 for obj2Element, and stick with the arrow functions. This completes our first solution. We have
const tabFieldMatches = (tab, id) { return tab === id; }
const hasMatchingTabField = (obj, id) => obj.some(e => tabFieldMatches(e.tab, id);
const findMatches = obj => obj.some(e => hasMatchingTabField(e1, obj.id));
And we call this using findMatches(obj1).
Old-fashioned array
But perhaps all these maps and somes are a little too much for you at this point. What ever happened to good old-fashioned for-loops? Yes, we can write things this way, and some people might prefer that alternative.
top: for (e1 of obj1) {
for (e2 of (obj2) {
if (e1.id === e2.tab) {
console.log("found match");
break top;
}
}
console.log("didn't find match);
}
But some people are sure to complain about the non-standard use of break here. Or, we might want to end up with an array of boolean parallel to the input array. In that case, we have to be careful about remembering what matched, at what level.
const matched = [];
for (e1 of obj1) {
let match = false;
for (e2 of obj2) {
if (e1.id === e2.tab) match = true;
}
matched.push(match);
}
We can clean this up and optimize it bit, but that's the basic idea. Notice that we have to reset match each time through the loop over the first object.

Trouble with Bootstraps typeahead in angular 5

I am having a difficult time getting Bootstraps typeahead in angular 5 working would appreciate some advice. The problem I have is that I don't know how to set the input field to equal the city + state for exaple "New york, NY" in bootstraps search method example. I am new to Typescript and the new fat arrow feature in JavaScript any help would be greatly appreciated.
model array of objects
public model: any;
example of data that I am getting
{
"city":"New York",
"latitude":40.7127837,
"longitude":-74.0059413,
"state":"New York",
"stateCode":"NY"
}
Search method here I am trying to set the location items to filter 'city,'+'state'
search = (text$: Observable<string>) => text$
.debounceTime(200)
.distinctUntilChanged()
.map(term => term.length < 2 ? [] : this.locationItems.filter(item => item.city.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10));
The arrow function inside the last map in your chain needs to map (transform) the value of the string the user has typed into the search box to an array of items that will be presente to the user as suggestions.
You start nice, by askin if term is only one character long (or an empty string) and do nt even run the search, imediatelly returning empty array. For the other part, you need to find which items you want to present to the user.
This part depends on your business logic, but I assume that you want user to be searching by either state or stateCode? Anyway, this part is your business logic and you can change and improve it according to your busniess model. I'm giving a very simply function in the code below.
// util function
// returns true if the "term" can be used to match the "item" from your data
// change this according to your business logic
function matches(term: string, item: Item): boolean {
return item.state.toLowerCase().includes(term.toLowerCase())
|| item.stateCode.toLowerCase().includes(term.toLowerCase())
}
The lambda in the last map can be like this.
term => {
if (term.length < 2) {
return []
}
// arary of matching results
const matching = this.filter(item => matches(term, item))
// now we transform this to the format you specified
const formatted = matching.map(item => `${item.state}, ${item.stateCode}`)
return formatted
// you can also .slice(0, 10) here like you did in your example to keep the number of suggestions no more than 10
}

Categories

Resources