Data Structures & Algorithms FAQ: Top Questions
2. Simulate Event Delegation in a DOM Tree
In real browsers, event delegation is a powerful technique where a single listener is attached to a parent element to handle events from its children. This saves memory and improves performance.
In this simulation, we mimic event delegation by allowing parent nodes to handle events that originate from any of their descendants. This simulates how one container can "listen" for events from deeply nested children.
🧭 Step-by-Step Instructions:
- Traverse from the root to the target node to record the full path.
- Only collect delegated listeners from the ancestors of the target (including the target).
- For each node in the path, if it has a
delegatedlistener, include it in the final result.
📥 Example Input:
const domTree = {
id: "root",
listeners: { delegated: ["onRootDelegated"] },
children: [
{
id: "container",
listeners: { delegated: ["onContainerDelegated"] },
children: [
{
id: "button",
listeners: {},
children: []
}
]
}
]
};
const targetId = "button";
🎯 Expected Output:
Since the event occurs at button, we collect delegated listeners from all ancestors, starting from root to button.
[
"onRootDelegated",
"onContainerDelegated"
]
✅ TypeScript Solution (with Comments):
type Node = {
id: string;
listeners?: { delegated?: string[] };
children: Node[];
};
function simulateEventDelegation(tree: Node, targetId: string): string[] {
const path: Node[] = [];
// Step 1: Build path to target using DFS
function dfs(node: Node, currentPath: Node[]): boolean {
currentPath.push(node);
if (node.id === targetId) {
path.push(...currentPath);
return true;
}
for (const child of node.children) {
if (dfs(child, [...currentPath])) return true;
}
return false;
}
dfs(tree, []);
// Step 2: Collect delegated listeners from all nodes in the path
const result: string[] = [];
for (const node of path) {
if (node.listeners?.delegated) {
result.push(...node.listeners.delegated);
}
}
return result;
}
📘 Detailed Explanation:
- This simulation skips the concept of separate capture and bubble phases — instead, it reflects how delegated event handlers catch events from descendants.
- It's especially useful in real-world UIs where thousands of child elements may trigger clicks — rather than attaching thousands of listeners, we attach one to their common ancestor.
- This is a pure top-down path traversal that mimics listener resolution.
🛠️ Real-World Use Cases:
- Virtual DOM frameworks (React synthetic events, Vue, etc.)
- Dynamic UIs where elements are frequently added/removed
- Performance tuning in large apps (e.g., single listener on
document.body)
