Interactive Node Tree in Vue.js with TypeScript
This challenge focuses on building a dynamic, interactive node tree within a Vue.js application using TypeScript. You'll be creating a component that allows users to add, delete, and potentially move nodes within the tree structure, providing a practical exercise in component design, data management, and reactivity in Vue.js. This is a common pattern in applications dealing with hierarchical data, such as file explorers, organizational charts, or decision trees.
Problem Description
You are tasked with creating a Vue.js component called NodeTree that displays and allows manipulation of a tree structure represented as a nested array of objects. Each node object has the following properties:
id: A unique string identifier for the node.name: A string representing the node's label.children: An optional array of node objects representing the node's children. If a node has no children, this property should be omitted or an empty array.
The NodeTree component should:
- Display the tree: Render the tree structure visually, with nodes nested appropriately. A simple visual representation (e.g., using indentation or icons) is sufficient.
- Add a node: Provide a button or input field to add a new node as a child of the currently selected node. The new node should have a unique
idand anameprovided by the user. If no node is selected, the new node should be added as the root of the tree. - Delete a node: Provide a mechanism (e.g., a button or context menu option) to delete a selected node. Deleting a node should also remove all its children.
- Node Selection: Allow the user to select a node. The selected node should be visually indicated (e.g., with a different background color or border). The "Add Node" functionality should operate on the currently selected node.
- Root Node Handling: Ensure that the root node(s) are handled correctly when adding or deleting nodes.
Expected Behavior:
- The component should be reactive. Changes to the tree data (adding, deleting, or modifying nodes) should immediately update the displayed tree.
- The component should handle empty trees gracefully.
- The component should prevent adding nodes with duplicate IDs.
- Deleting a node should not leave dangling references in the tree.
Examples
Example 1:
Input:
const treeData = [
{
id: 'root1',
name: 'Root 1',
children: [
{
id: 'child1',
name: 'Child 1'
},
{
id: 'child2',
name: 'Child 2',
children: [
{
id: 'grandchild1',
name: 'Grandchild 1'
}
]
}
]
}
];
Output:
A visual representation of the tree structure, with "Root 1" as the root, "Child 1" and "Child 2" as its children, and "Grandchild 1" as a child of "Child 2". The user can select any node and add a new child to it.
Explanation: The component renders the nested structure, allowing for node selection and addition of new nodes as children of the selected node.
Example 2:
Input:
const treeData: any[] = [];
Output:
An empty tree view. The "Add Node" button should still be functional, adding a new root node.
Explanation: The component handles the case where the tree is initially empty.
Example 3: (Edge Case - Deleting Root Node)
Input:
const treeData = [
{
id: 'root1',
name: 'Root 1'
}
];
Output:
An empty tree view.
Explanation: Deleting the root node should result in an empty tree.
Constraints
- Data Structure: The tree data must be represented as a nested array of objects with the
id,name, andchildrenproperties as described above. - Unique IDs: Ensure that all node IDs are unique within the entire tree. The component should prevent the addition of nodes with duplicate IDs.
- Vue Version: Use Vue 3.
- TypeScript: The solution must be written in TypeScript.
- Performance: While not a primary focus, avoid excessively complex rendering logic that could lead to performance issues with large trees (e.g., > 100 nodes). Consider using Vue's reactivity system effectively.
- UI: The visual representation of the tree can be simple (e.g., indentation, basic styling). Focus on the functionality rather than elaborate UI design.
Notes
- Consider using Vue's
v-fordirective to recursively render the tree structure. - Use Vue's reactivity system (
reforreactive) to ensure that changes to the tree data are reflected in the UI. - Think about how to efficiently handle node selection and updating the UI when a node is selected.
- You can use a simple library or custom logic to generate unique IDs for new nodes. Avoid using the same ID for multiple nodes.
- Error handling (e.g., displaying messages when a node cannot be deleted due to constraints) is not required for this challenge, but is good practice.