0

I have a function that should filter the list of contact. Logic is that if its at least one of props passed will compare to input, it will pass. now i got only this code that compares to first+last name. I`m a bit confused, is there an effective way to do it with iteration through all props(which can be object with other props)?

handleSearch(event){
   let CONTACTS = this.props.items;
   let inputValue = event.target.value; //dan

   var displayedUsers = CONTACTS.filter(el => {

      var searchValue = el.general.firstName + el.general.lastName; //this should be changed to el.allProps
      return searchValue.indexOf(inputValue) !== -1; //
   });

   this.setState({displayedUsers: displayedUsers}); //will return dan, danone dante etc.
}
  • It's hard to tell what data is in each `el`. What is `el.allProps`? What is `this.props.items` and do you want to exclude that from the filter? – Chase DeAnda May 18 '18 at 15:54
  • There are a number of ways to achieve this, I would write a recursive function and you can make use of [Object.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) or may be a [for ... in loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) to iterate your object, in case you find another object, that's where the recursion comes in. – Mark E May 18 '18 at 15:54
  • Here you can find a very similar approach, just compare against value instead of key https://stackoverflow.com/questions/40603913/search-recursively-for-value-in-object-by-property-name – Mark E May 18 '18 at 15:57
  • el/allProps is pseudocode which means that filter method should take all props that el had, not only general.firstName + lastName – Гриша Кисенко May 18 '18 at 15:58

4 Answers4

0

You can use Object.values() and iterate over all values.

handleSearch(event){
   const contracts = this.props.items;
   const val = event.target.value;

   var displayedUsers = contracts.filter(contract => Object.values(contract).find(val))

   this.setState({displayedUsers});
}

If your contract object contains nested objects that should also be searched for this gets a little more tricky.

trixn
  • 15,761
  • 2
  • 38
  • 55
0

If you can use ES2017 covert the object to an array so you can use the array methods.

MDN Object.values()

Check if object has certain values:

const hasValue = Object.values(object).some(x => (x === searchValue)); // returns boolean

MDN Array.some() MDN Array.every()

Return the found values in an array:

const hasValue = Object.values(object).filter(x => (x === searchValue)); // returns found values

MDN Filter

You can also use them in maps to search in two array's:

const newArray = array1.map(x => { const exists = array2.some(y => y.value === x.value); if (exists) { do something } // Or whatever you wanna do ofc. }

PVermeer
  • 2,631
  • 2
  • 10
  • 18
0

You can use the Object.keys function to get an array of all the props in each element, and run another filter on that for a match. Since you mention that some of the props can be objects, you'll need to use a recursive function to search every prop in your object tree. If something matches, that array will have some entries in it so you will use that as the result for you outer filter.

Here's an example of how the handleSearch function could end up being:

handleSearch(event) {
    let CONTACTS = this.props.items;
    let inputValue = event.target.value;

    let searchObject = (obj, searchTerm) => {
        return Object.keys(obj).filter(prop => {
            if (typeof obj[prop] === 'object') {
                return searchObject(obj[prop], searchTerm).length > 0;
            } else {
                return obj[prop].indexOf(searchTerm) !== -1
            }
        }).length > 0;
    }
    let displayedUsers = CONTACTS.filter( el => searchObject(el, inputValue);
    this.setState({displayedUsers});
}

This assumes you only have strings and objects in the CONTACTS variable. If you have functions, arrays, or something else, you'll have to update the if / else statements to account for those.

Murad Khan
  • 401
  • 2
  • 8
  • This doesnt work, i think bcs if its throws at least one -1, element doesnt shows. instead of this, it should be if at least one of the obj[prop].indexOf(searchTerm) throws something different from -1, function will stop and return data. Im not very comfortable with recursion, so can you help me please? – Гриша Кисенко May 18 '18 at 16:36
0

not single one of examples work for me, so i decided to turn my object into an array of props, and then just iterate them with for loop. I think it can be written better than i do, but it works for me so i just show you.

handleSearch(event){
let CONTACTS = this.props.items;
let inputValue = event.target.value;

let iterate = function(obj, callback) { //this is recursion iterator method with callback func
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            if (typeof obj[property] == "object") {
                iterate(obj[property], callback);
            } else {
                callback(obj[property]);
            }
        }
    }
}

var displayedUsers = CONTACTS.filter(el => { //here i leave object that will pass the indexOf method below.
  //console.log(el);
let arr = [];

iterate(el, function (e) {
     arr.push(e);
});

for (var i = 0; i < arr.length; i++) {
    if(arr[i].toLowerCase().indexOf(inputValue) !== -1){
      foundInfo = arr[i];
      return arr[i];
    }
  }
});

this.setState({displayedUsers: displayedUsers});

}