WIDGET DUPLICATION FIX
Documentation for Sessions
Widget Duplication Fix - Session 12.14
Problem
When using the Hierarchy section in the Properties Panel to assign a parent to a widget (e.g., moving a Text Widget into a Container Widget), the widget was being rendered twice:
- Once on the canvas (as a top-level widget)
- Once inside the container (as a child widget)
This caused visual duplication where users would see two copies of the same widget.
Root Cause
The editor-canvas.component.html template was rendering ALL widgets from the widgets() array:
@for (widget of widgets(); track trackByWidgetId($index, widget)) {
<!-- ... widget rendering ... -->
}
However, when a widget has a parentId, it should:
- ✅ Be rendered by its parent container (via
childWidgetsinput) - ❌ NOT be rendered at the canvas level
The canvas was not filtering out child widgets, causing them to be rendered in both places.
Solution
1. Added topLevelWidgets Computed Signal
File: libs/libs-widgets/widgets/src/lib/widgets/editor-canvas/editor-canvas.component.ts
// 🎯 Computed: Only top-level widgets (no parentId) - child widgets are rendered by their containers
readonly topLevelWidgets = computed(() => {
const allWidgets = this.widgets();
const topLevel = allWidgets.filter(w => !w.parentId);
console.log('[Canvas] 🎯 Top-level widgets:', topLevel.length, '/', allWidgets.length);
return topLevel;
});
This computed signal:
- Filters the main
widgetsarray - Returns only widgets without a
parentId - Logs the count for debugging
2. Updated Template to Use Top-Level Widgets
File: libs/libs-widgets/widgets/src/lib/widgets/editor-canvas/editor-canvas.component.html
<!-- Widgets (Top-Level Only - children rendered by container widgets) -->
@for (widget of topLevelWidgets(); track trackByWidgetId($index, widget)) {
<!-- ... widget rendering ... -->
}
Now the canvas only renders top-level widgets. Child widgets are automatically rendered by their parent containers through the existing [childWidgets]="getChildWidgets(widget.id)" mechanism.
Testing
Before Fix
- Create a Text Widget on canvas
- Open Properties Panel → Hierarchy section
- Select "Container Widget" from Parent Widget dropdown
- Result: Text widget appears TWICE (once on canvas, once in container)
After Fix
- Create a Text Widget on canvas
- Open Properties Panel → Hierarchy section
- Select "Container Widget" from Parent Widget dropdown
- Result: Text widget appears ONCE (only inside the container)
- Text widget is removed from top-level canvas rendering
Architecture Notes
Widget Rendering Hierarchy
Canvas (editor-canvas.component)
└─ Renders: widgets with NO parentId (topLevelWidgets)
├─ Text Widget 1 (parentId: undefined) ✅ Rendered by canvas
├─ Container Widget (parentId: undefined) ✅ Rendered by canvas
│ └─ Text Widget 2 (parentId: container.id) ❌ NOT rendered by canvas
│ └─ Rendered by container via childWidgets ✅
└─ Button Widget (parentId: undefined) ✅ Rendered by canvas
Key Principles
- Canvas renders top-level widgets only (no
parentId) - Containers render their own children (via
childWidgetsprop) - Children are stored in main
widgetsarray but filtered from canvas rendering - Parent-child relationships tracked via
parentIdandchildrenarray
Related Files
- ✅
libs/libs-widgets/widgets/src/lib/widgets/editor-canvas/editor-canvas.component.ts- AddedtopLevelWidgetscomputed - ✅
libs/libs-widgets/widgets/src/lib/widgets/editor-canvas/editor-canvas.component.html- Updated template - ✅
libs/libs-ui/editor-ui/src/lib/components/properties-panel/properties-panel-new.component.ts- Hierarchy UI - ✅
libs/libs-ui/editor-ui/src/lib/components/editor-ui/editor-ui.component.ts-handleWidgetReparentmethod
Next Steps
- ✅ Verify that the Parent Selector UI works correctly (no duplication)
- ⏳ Implement drag-and-drop based re-parenting
- ⏳ Test palette → container drop functionality
Session Progress
Session 12.14 - Fixed widget duplication by implementing topLevelWidgets computed signal.