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?