0% found this document useful (0 votes)
4 views3 pages

Framework 2

The document outlines several major issues with the dashboard builder, including problems with dynamic chart adding/deleting, chart resizing, overlapping charts, minimum size constraints, and initialization race conditions. Each issue is accompanied by symptoms and detailed recommended fixes, such as using the GridStack API for managing widgets, implementing a ResizeObserver for charts, and ensuring proper initialization with Angular's @ViewChildren. These fixes aim to enhance the functionality and user experience of the dashboard builder.

Uploaded by

gawobes335
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views3 pages

Framework 2

The document outlines several major issues with the dashboard builder, including problems with dynamic chart adding/deleting, chart resizing, overlapping charts, minimum size constraints, and initialization race conditions. Each issue is accompanied by symptoms and detailed recommended fixes, such as using the GridStack API for managing widgets, implementing a ResizeObserver for charts, and ensuring proper initialization with Angular's @ViewChildren. These fixes aim to enhance the functionality and user experience of the dashboard builder.

Uploaded by

gawobes335
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

Here is a document detailing the issues found in the dashboard builder and their

recommended fixes.
________________

1. Major Issue: Dynamic Chart Adding/Deleting Fails


Problem:
The addChart() and deleteChart() methods do not correctly interact with the
GridStack library.
* On Add: The addChart() method just pushes a new config to the dashboard.charts
array. Angular's *ngFor creates the new DOM element, but the GridStack instance
(which was initialized once on load) is unaware of this new element.
* On Delete: The deleteChart() method filters the array, and Angular removes the
DOM element. This also happens without GridStack's knowledge, which can lead to
errors or an invalid internal layout state.
Symptoms:
* Newly added charts appear on the dashboard but are static. They cannot be
dragged, resized, or automatically positioned.
* Deleting charts might work visually but can corrupt GridStack's internal model.
How to Fix:
You must use the GridStack API to manage widgets imperatively when adding or
removing them.
* For addChart():
1. After pushing the newChart to the dashboard.charts array, you must wait for
Angular to render the new element (e.g., using setTimeout(0) or by subscribing to a
@ViewChildren QueryList.changes).
2. Find the new DOM element (e.g., this.grid.getGridItems().find(...)).
3. Call this.grid.makeWidget(newElement) to have GridStack "adopt" and manage
it.
* For deleteChart():
1. Find the DOM element corresponding to the chartId (e.g.,
this.grid.getGridItems().find(el => el.getAttribute('gs-id') === chartId)).
2. If the element is found, call this.grid.removeWidget(element).
3. After GridStack has removed the widget, you can then safely filter your
dashboard.charts array as you do now.
________________

2. Major Issue: Charts Don't Resize


Problem:
The ChartComponent (using ECharts) only resizes itself when the browser window
resizes. It has no way of knowing that its parent grid-stack-item has been resized
by the user dragging a handle.
Symptom:
When you resize a dashboard panel, the panel itself gets bigger or smaller, but the
chart graphic inside remains its original size, leading to empty space or clipping.
How to Fix:
Use a ResizeObserver inside chart.component.ts to watch the chart's container for
size changes.
1. In chart.component.ts, declare a new private property: private resizeObserver:
ResizeObserver | null = null;.
2. In ngAfterViewInit() (or initChart()), create the observer:
3. TypeScript
* private initChart() {
* if (!this.config || !this.chartElement) return;
* * this.chart = echarts.init(this.chartElement.nativeElement);
* const data = this.dashboardService.getChartData(this.config.type);
* this.chart.setOption(data);
* * // --- FIX ---
* this.resizeObserver = new ResizeObserver(() => {
* if (this.chart) {
* this.chart.resize();
* }
* });
* this.resizeObserver.observe(this.chartElement.nativeElement);
* // -----------
* * // You can now remove the 'window.addEventListener' for resize
* }
4. 5. In ngOnDestroy(), disconnect the observer:
6. TypeScript
* ngOnDestroy() {
* if (this.chart) {
* this.chart.dispose();
* }
* if (this.resizeObserver) { // <-- Add this
* this.resizeObserver.disconnect();
* }
* // window.removeEventListener('resize', this.handleResize.bind(this)); //
Remove this
* }
7. ________________

3. Issue: New Charts Overlap Existing Charts


Problem:
The addChart() method in dashboard.component.ts hardcodes the position of every new
chart to x: 0, y: 0. This causes all new charts to appear in the top-left corner,
overlapping any chart that is already there.
Symptom:
Clicking "Add Chart" makes the new chart appear directly on top of the "Sales Data"
chart.
How to Fix:
Use GridStack's autoPosition feature. This is best combined with the fix for Issue
#1.
When you add the widget, tell GridStack to find a free spot.
1. In dashboard.component.ts, modify addChart().
2. When you call this.grid.makeWidget(newElement) (from the fix for Issue #1), you
can pass options. GridStack is often smart enough to auto-position if it's placed
on a busy spot, but to be explicit:
* Remove x: 0, y: 0 from the newChart config object.
* Instead, call this.grid.addWidget({ w: 6, h: 4, autoPosition: true, ... }).
This is the cleanest way. This method will create and return the element for you.
* You would then need to attach your Angular component to that element, which is
more complex (requires ViewContainerRef).
Simpler Fix (building on Fix #1):
When you call this.grid.makeWidget(newElement), GridStack should automatically move
it if (0, 0) is occupied. The key is that the grid.on('change', ...) event handler
will then fire, and your existing code will update the chart's x and y properties
to reflect its new, non-overlapping position.
________________

4. Issue: Charts Can Be Resized Too Small


Problem:
There is no minimum size set for the charts. A user can resize a chart to be 1x1,
making it useless and difficult to grab.
Symptom:
Charts can be shrunk to a tiny, unusable size.
How to Fix:
Set a minW (minimum width) and minH (minimum height) in the GridStack
initialization options.
1. In dashboard.component.ts, find the initGrid() method.
2. Add minW and minH to the GridStack.init() options object:
3. TypeScript
* private initGrid() {
* this.grid = GridStack.init({
* cellHeight: 70,
* acceptWidgets: true,
* removable: false,
* resizable: { handles: 'e, se, s, sw, w' },
* draggable: { handle: '.chart-titlebar' },
* * // --- FIX ---
* minW: 4, // e.g., minimum 4 columns wide
* minH: 3 // e.g., minimum 3 rows high
* // -----------
* });
* // ...
* }
4. ________________

5. Issue: Initialization Race Condition


Problem:
ngAfterViewInit() in dashboard.component.ts uses setTimeout(100) to initialize the
grid. This is a "code smell" that indicates a race condition. It's guessing that
100ms is enough time for Angular's *ngFor to render the initial chart elements.
Symptom:
On a slow device or under heavy load, 100ms may not be enough time.
GridStack.init() could run before the grid-stack-item elements are in the DOM,
resulting in an empty or broken dashboard.
How to Fix:
Use @ViewChildren to wait for Angular to confirm the elements have been rendered.
1. In dashboard.component.ts, add imports for ViewChildren, QueryList, and
ElementRef.
2. Add a @ViewChildren property to query for the items:
3. TypeScript
* @ViewChildren('.grid-stack-item') gridItems!: QueryList<ElementRef>;
4. 5. Modify ngAfterViewInit() to subscribe to the query list:
6. TypeScript
* ngAfterViewInit() {
* // setTimeout(() => this.initGrid(), 100); // <-- Remove this
* * // --- FIX ---
* // Subscribe to changes. 'first()' ensures this only runs once.
* this.gridItems.changes.pipe(first()).subscribe(() => {
* this.initGrid();
* });
* }
7. 8. Note: You may need to import first from rxjs/operators. A simpler (but
slightly less robust) alternative is setTimeout(() => this.initGrid(), 0), which
just waits for the next browser tick.
*

You might also like