0

I was trying to search for function. This function checks the nested array, which has multiple strings, then returns if the array has a search word.

The data structure of the array

[
  {
   name:'aa',
   searchWords:['aa','ab','bc'] <- I want to use this array for search
  },
  {
   name:'bb',
   searchWords:['bb','bc','de'] <- I want to use this array for search
  },
...
]

I tried to use indexOf function.
However, I couldn't display any components with this code below.
But I changed target value from item.searchWords to item.name in the code. it worked.

HTML
<div className="itemWrapper">
     {filterItems.map((item, idx) => (
            <Item key={idx} {...item} id={idx} list={list} />
      ))}
</div>    


Js
const filterItems = list.filter(
      (item) => item.searchWords.indexOf(searchWord) !== -1,
    );

My desired result is that search result update in realtime.
For instance with the same data structure above, when the user searches 'a', searchWords 'aa' and 'ab' returns true for displaying the item,

Thank you so much for your help.

6
  • I think you can further down reduce your example to pure js since apparently your filtering just involves js. Your filtering to me is correct (except you should use includes instead of indexOf (but that should not change your problem). Can you show us what is searchWord's value? (typically if it was a it would match item.name (with say first letter) but not any word of item.searchWords) Commented Oct 25, 2019 at 5:17
  • Please share the expected output for a given input. Commented Oct 25, 2019 at 5:18
  • @user753643 thank you for your comment. original searchWord:["Luke Skywalker"]. Users can add new words to this array freely. so the array could be ["Luke Skywalker","bobahead"].any type of strings would be contained. Commented Oct 25, 2019 at 5:24
  • @HassanImam Thank you for your comment. expected input is String. Commented Oct 25, 2019 at 5:24
  • what if the search character is b? Commented Oct 25, 2019 at 5:27

5 Answers 5

1

You can try with find() and includes() on name property of the object and finally filter().

Demo:

var list = [
  {
   name:'aa',
   searchWords:['aa','ab','bc'] 
  },
  {
   name:'bb',
   searchWords:['bb','bc','de']
  }
]

document.getElementById('searchWord').addEventListener('input', function(){
  console.clear();
  var filterItems = list.find(item => item.name.includes(this.value));
  filterItems = filterItems ? filterItems.searchWords : [];
  filterItems = filterItems.filter(i => i.includes(this.value));
  console.log(filterItems);
});
<input id="searchWord"/>

Sign up to request clarification or add additional context in comments.

Comments

1

You need to loop over the searchWords array to find if it matches the search word. This one will work
const filterItems = list.filter( (item) => item.searchWords.filter((myWord) => myWord.indexOf(searchWord)>-1) );

1 Comment

and if it works, please accept or upvote ^^, I would appreciate ^^
0

The issue with the code is that its trying to find if the array contains a word when you use indexOf. Eg: When you search for 'a', the code checks is there is any word 'a' in the array and not any word containing letter 'a'.

You need to change the JS part to :

Js

const list = [{
    name: 'aa',
    searchWords: ['aa', 'ab', 'bc']
  },
  {
    name: 'bb',
    searchWords: ['bb', 'bc', 'de']
  }
];

let searchWord = "a";

const filterItems = list.filter(
  (item) => item.searchWords.filter(word => word.includes(searchWord)).length > 0
);

document.getElementById('result').innerHTML = JSON.stringify(filterItems);
<p id="result">
  </>

2 Comments

Thank you so much. this one also works very well. I have a question, how come check if the length is more than one?
if the searchWords array does not contain any string which includes the searchWord, the filter function will return empty array. That's why is have checked for length.
0

You can use array#reduce and filter searchWords array using the array#filter by checking the search words.

const dataSource = [{
      name: 'aa',
      searchWords: ['aa', 'ab', 'bc']
    },
    {
      name: 'bb',
      searchWords: ['bb', 'bc', 'de']
    }
  ],
  searchWord = 'a',
  result = dataSource.reduce((res, {name, searchWords}) => {
    let matched = searchWords.filter(word => word.includes(searchWord));
    if(matched.length) {
      res.push({name, searchWords: matched});
    }
    return res;
  },[])

console.log(result);

1 Comment

Thank you for your solution.this one is excellent. However, I wanted to try to keep things neat I'll use the filter.
0

It is because, how indexOf works, with array and strings.

let's say syntax of indexOf is

operatedItem.indexOf(searchedItem);

Here, in your case

{
   name:'bb',
   searchWords:['bb','bc','de']
}

name is a string,

and searchWords is an array.

When you perform:

name.indexOf("b"); //0

name.indexOf("bb"); //0

name.indexOf("a"); //-1

It will check if the searchedItem exists anywhere in operatedItem.

let str = "aa ab a bb";

console.log(str.indexOf("a")); //0

console.log(str.indexOf("aa")); //0

console.log(str.indexOf("ab")); //3

console.log(str.indexOf("b")); //4

console.log(str.indexOf("c")); //-1

console.log(str.indexOf("aaa")); //-1

And when indexOf is used with array,

it checks if a searchedItem exists in the operatedItem array, it will not go for substring search.

let arr = ["aa", "ab", "a", "bb"];

console.log(arr.indexOf("a")); //2

console.log(arr.indexOf("aa")); //0

console.log(arr.indexOf("ab")); //1

console.log(arr.indexOf("b")); //-1

console.log(arr.indexOf("c")); //-1

console.log(arr.indexOf("aaa")); //-1

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.