The title may not be the most descriptive, but I struggled to find a better way to convey my issue.
I've encountered a problem multiple times while working with angular. To illustrate, let's consider this scenario:
Imagine having a main component called MomComponent
, which contains several instances of KidComponent
.
Each KidComponent
can be resized by the user, and if one is resized, all others should adjust accordingly.
A KidComponent
should also function independently without any sibling components.
Here is a snippet of my code:
// mom.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-mom',
templateUrl: './mom.component.html',
})
export class MomComponent {
width: number;
}
<!-- mom.component.html -->
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
// kid.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-kid',
templateUrl: './kid.component.html',
})
export class KidComponent {
@Input() set width(w: number) {
this._width = w;
this.draw();
}
@Output() widthChange = new EventEmitter<number>();
private _width = 100;
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
this._width = newWidth;
this.draw();
}
draw() {
// Drawing logic
}
}
The issue here is that the resized kid component gets drawn twice - once due to internal calls and again because the mom's width
variable updates.
To avoid this redundancy, I could modify the kid component like so:
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
// Removed these two lines:
//
// this._width = newWidth;
// this.draw();
}
// [...]
}
However, this modification would prevent me from using KidComponent
individually without sharing width information with other kids.
The current solution I have in mind involves:
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
if (!this.widthChange.observers.length) {
// If there are no listeners for the event, then redraw internally
this._width = newWidth;
this.draw();
} else {
// If there are listeners, assume they will handle redrawing
}
}
// [...]
}
Although functional, I am not entirely satisfied with this approach as just having an observer on widthChage
emitter doesn't guarantee proper redrawing of the KidComponent
.
So, my question remains: Is there a more effective approach that I might be overlooking?
Thanks!