react-arborist
react-arborist copied to clipboard
Including all the matching node's children in the search result
Hey.
Currently the matching function will only add the children that also match the search criteria.
However, I wonder how hard it would be to also provide the possibility to set up the matching to show all the children of matching nodes, regardless if they also match or not.
For example, if I search for "Issue Example", I would like this whole thing to appear:
For my use case, where the user can select both the parent and its children, the current behavior makes it impossible for them to list the children by searching for the more generic parent, which can be very useful.
I had to change the flattenAndFilterTree function and use patch-package to be able to use it that way, but I believe this use-case might not be that much specific so it might be worth adding the support to the library.
My code base also includes the changes from https://github.com/brimdata/react-arborist/pull/185 as I was having trouble with doing the matches with just the id, since my data can have repeated ids. If we can use truly unique keys, it works much better. Sharing below what I personally did in case it's useful to someone or for the feature request.
modified flattenAndFilterTree
function flattenAndFilterTree<T>(
root: NodeApi<T>,
isMatch: (n: NodeApi<T>) => boolean
): NodeApi<T>[] {
const matches: Record<string, boolean> = {};
const list: NodeApi<T>[] = [];
function matchChildren(children: NodeApi<T>[]) {
children?.forEach((child) => {
matches[child.key] = true;
if (child.children) {
matchChildren(child.children);
}
});
}
function markMatch(node: NodeApi<T>) {
const yes = !node.isRoot && isMatch(node);
if (yes) {
// match the current node
matches[node.key] = true;
let parent = node.parent;
// match the parents
while (parent) {
matches[parent.key] = true;
parent = parent.parent;
}
// match the children
if (node.children) {
matchChildren(node.children);
}
}
if (node.children) {
for (let child of node.children) markMatch(child);
}
}
function collect(node: NodeApi<T>) {
if (node.level >= 0 && matches[node.key]) {
list.push(node);
}
if (node.isOpen) {
node.children?.forEach(collect);
}
}
markMatch(root);
collect(root);
list.forEach(assignRowIndex);
return list;
}
Does this make sense? Any interest in making this work?
Just realized this is a duplicate of https://github.com/brimdata/react-arborist/issues/111 - though that one is already closed, so maybe it's worth to keep this discussion open. I did not try creating a matcher using the searchMatch option. If I'm able to, might be something to document here.
I've found a solution that works, potentially janky though:
searchMatch={(node, searchTerm) => {
// If the node itself matches the search term
if (searchMatch(node, searchTerm)) {
trueMatches.add(node.id)
return true
}
// If the node is the child of a matching element
if (trueMatches.has(node.parent?.id)) {
return true
}
// TODO: Grandchildren?
return false
}}
I have some complicated logic for determining a match, so I extracted it into a function called searchMatch. If the node itself matches, I add its ID to a set, and return true. If the node itself doesn't match, but it's parent's ID is in the set, then it's the child of a match, and I return true.
This implementation only includes the first generation (which is fine for my application), but recursion should be able to find a child at any depth 👍
The inclusion of the set slightly complicates things too, like you'll have to clear your set every time you clear your search term, etc.
Hi, I had figured out a solution to do this, had posted at #177. You may consider the solution and modify yourself.
Yeah, I should at least put some docs up on how to perform these types of filtering. This has come up three times now.
@lsfgrd Hi dear friend. Can you help me? According to the tree structure that you have asked and placed in your question, you have used a check box. Please guide me with example how can I manage selected by putting check box? I have opened a topic about the checkbox in the link below, please guide me there.
https://github.com/brimdata/react-arborist/issues/190