0

I'm trying to implement tree view search using JavaScript. I found search filter in treeview useful, but the answer provided there wasn't the expected output in my scenario.

Example input:

[
    {
        "id": 1,
        "templateName": "Item 1",
        "isFolder": "true",
        "children": [
            {
                "id": 2,
                "templateName": "Subitem 1",
                "isFolder": "true",
                "children": [
                    {
                        "id": 3,
                        "templateName": "Misc 1",
                        "isFolder": "true",
                        "children": [
                            {
                                "id": 4,
                                "templateName": "Misc 2"
                            }
                        ]
                    }
                ]
            },
            {
                "id": 5,
                "templateName": "Subitem 2",
                "isFolder": "true",
                "children": [
                    {
                        "id": 6,
                        "templateName": "Misc 3"
                    }
                ]
            }
        ]
    },
    {
        "id": 7,
        "templateName": "Item 2",
        "isFolder": "true",
        "children": [
            {   
                "id": 8,
                "templateName": "Subitem 1",
                "isFolder": "true",
                "children": [
                    {
                        "id": 9,
                        "templateName": "Misc 1"
                    }
                ]
            },
            {
                "id": 10,
                "templateName": "Subitem 8",
                "isFolder": "true",
                "children": [
                    {
                        "id": 11,
                        "templateName": "Misc 4"
                    },
                    {
                        "id": 12,
                        "templateName": "Misc 5"
                    },
                    {
                        "id": 13,
                        "templateName": "Misc 6",
                        "isFolder": "true",
                        "children": [
                            {
                                "id": 14,
                                "templateName": "Misc 7"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

If I search for Subitem 1, then the expected output is:

[
    {
        "id": 1,
        "templateName": "Item 1",
        "isFolder": "true",
        "children": [
            {
                "id": 2,
                "templateName": "Subitem 1",
                "isFolder": "true",
                "children": [
                    {
                        "id": 3,
                        "templateName": "Misc 1",
                        "isFolder": "true",
                        "children": [
                            {
                                "id": 4,
                                "templateName": "Misc 2"
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        "id": 7,
        "templateName": "Item 2",
        "isFolder": "true",
        "children": [
            {   
                "id": 8,
                "templateName": "Subitem 1",
                "isFolder": "true",
                "children": [
                    {
                        "id": 9,
                        "templateName": "Misc 1"
                    }
                ]
            }
        ]
    }
]

But the answer in the referenced Q&A returns objects without children properties.

I tried to modify that answer's code and also I added isFolder props for additional validation for my help. But I cannot make it return the expected output above.

4
  • Can you add your actual code? Commented Jul 2, 2021 at 17:53
  • 1
    Please make sure the question contains the problem statement. Although a link to another Q&A can be helpful, the essence should be in the current question. So far it is not specified what the input is, and expected output. An example of input/output would be useful. Also add the code you are trying with (you can always add attribution). Commented Jul 2, 2021 at 19:10
  • After your edit: why does the output have the same structure repeated? Shouldn't the id remain unique? Commented Jul 3, 2021 at 16:56
  • I edited output again. Nothing but removed the duplicate. If I search Subitem 1, it id inside Item 1. So I want the output Item 1 with only Subitem 1 and their children. Same, if subitem 1 where present in other child, I want that complete parent track Commented Jul 3, 2021 at 17:04

1 Answer 1

3

You could do this with a recursive function that copies the tree, but only retaining children that have a deeper match. When a node matches, no deeper recursion is needed, as then the whole subtree below that node remains included.

Here I have used map and a chained filter(Boolean). You could achieve the same with reduce. The map will map nodes to false when there is no match somewhere in the subtree rooted by that node. These false values are then eliminated by filter(Boolean):

function deepFilter(nodes, cb) {
    return nodes.map(node => {
        if (cb(node)) return node;
        let children = deepFilter(node.children || [], cb);
        return children.length && { ...node,  children };
    }).filter(Boolean);
}

const forest = [{"id": 1,"templateName": "Item 1","isFolder": "true","children": [{"id": 2,"templateName": "Subitem 1","isFolder": "true","children": [{"id": 3,"templateName": "Misc 1","isFolder": "true","children": [{"id": 4,"templateName": "Misc 2"}]}]},{"id": 5,"templateName": "Subitem 2","isFolder": "true","children": [{"id": 6,"templateName": "Misc 3"}]}]},{"id": 7,"templateName": "Item 2","isFolder": "true","children": [{"id": 8,"templateName": "Subitem 1","isFolder": "true","children": [{"id": 9,"templateName": "Misc 1"}]},{"id": 10,"templateName": "Subitem 8","isFolder": "true","children": [{"id": 11,"templateName": "Misc 4"},{"id": 12,"templateName": "Misc 5"},{"id": 13,"templateName": "Misc 6","isFolder": "true","children": [{"id": 14,"templateName": "Misc 7"}]}]}]}];

const result = deepFilter(forest, node =>
    node.templateName.includes("Subitem 1")
);

console.log(result);

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

3 Comments

Or, trade time for space and keep [...traverse(forest)] around as an index. And, if searching by templateName is a regular thing, reduce that array to an object keyed by templateName.
@trincot Thanks for answer and edited the question. I saw your code and output. But I want a output of complete tree structure if any match found. I added my expected output in the question. Please look into that
I have rewritten my answer.

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.