Home > front end >  How to search string in nested object and update the property for all child and parent
How to search string in nested object and update the property for all child and parent

Time:10-07

I have an array of objects in the hierarchical data structure. I need to check if any of the parents or children nodes contains a search string. I am able to filter the array, but I just want to update the matchFound property instead of applying the filter on the tree data.

Expected Result: If match is found, matchFound property of all the parent and children nodes should be true otherwise false.

treeData = [{
    name: 'Infiniti',
    matchFound: null,
    children: [{
        name: 'G50',
        matchFound: null,
        children: [{
            name: 'Pure AWD',
            matchFound: null,
          },
          {
            name: 'Luxe',
            matchFound: null,
          },
        ],
      },
      {
        name: 'QX50',
        matchFound: null,
        children: [{
            name: 'Pure AWD',
            matchFound: null,
          },
          {
            name: 'Luxe',
            matchFound: null,
          },
        ],
      },
    ],
  },
  {
    name: 'BMW',
    matchFound: null,
    children: [{
        name: '2 Series',
        matchFound: null,
        children: [{
            name: 'Coupé',
            matchFound: null,
          },

          {
            name: 'Gran Coupé',
            matchFound: null,
          },
        ],
      },
      {
        name: '3 Series',
        matchFound: null,

        children: [{
            name: 'Sedan',
            matchFound: null,
          },
          {
            name: 'PHEV',
            matchFound: null,
          },
        ],
      },
    ],
  },
];

filteredData = [];

function filter(searchString) {
  this.filteredData = this.search(this.treeData, searchString);
  console.log(this.filteredData)
}

function search(children, searchString) {
  return children.reduce((acc, item) => {
    if (item.name.toLowerCase().includes(searchString.toLowerCase())) {
      acc.push(item);
    } else if (item.children && item.children.length > 0) {
      const newItems = this.search(item.children, searchString);
      if (newItems.length > 0) {
        acc.push({
          name: item.name,
          children: newItems
        });
      }
    }

    return acc;
  }, []);
}

this.filter('infiniti');
this.filter('luxe');

CodePudding user response:

I can propose a solution wiht some assumptions:

  1. The filter method should return new tree structure, and should not modify the original one

  2. If any of the child nodes has match - all the parents are marked as matchFound=true

Here is a working playground

And I'll paste the meaningful parts of the code:

function filter(searchString: string) {
  return treeData.map(node => search(node, searchString)); 
}

function search(node: CarNode, searchString: string, foundInParent = false): CarNode {
  const matchFoundInNodeOrParent = foundInParent || node.name.toLowerCase().includes(searchString.toLowerCase());

  const children = node?.children?.map(child => search(child, searchString ,matchFoundInNodeOrParent));

  //match is found if parent or this node or at least one of th children has mathc found
  const matchFound = matchFoundInNodeOrParent || ( children !== undefined && children.some(child => child.matchFound));

  //return new object
  return children !== undefined ? { ...node, matchFound, children } : { ...node, matchFound };
}

  • Related