Skip to content

Instantly share code, notes, and snippets.

@ko1ebayev
Created March 13, 2024 11:10
Show Gist options
  • Save ko1ebayev/95db8d5bbb71c41bbaf00dcc7ffccf5d to your computer and use it in GitHub Desktop.
Save ko1ebayev/95db8d5bbb71c41bbaf00dcc7ffccf5d to your computer and use it in GitHub Desktop.
Empowered angular form control
type StatusChange = (property: string, previousValue: any, value: any) => void;
interface EmpoweredStatus {
property: string;
value: any;
previousValue: any;
}
class EmpoweredFormControl<T extends AbstractControl> {
private static readonly EMPOWER_KEY = '##empower##';
private statusChangeHandlers: StatuChange[] = [];
private empoweredStatusSubject = new Subject<EmpoweredStatus>();
static getEmpoweredControl<T extends AbstractControl>(abstractControl: T): EmpoweredFormControl<T> {
if (!abstractControl[EmpoweredFormControl.EMPOWER_KEY]) {
abstractControl[EmpoweredFormControl.EMPOWER_KEY] = new EmpoweredFormControl(abstractControl);
}
return abstractControl[EmpoweredFormControl.EMPOWER_KEY];
}
static destroyEmpoweredControl<T extends AbstractControl>(abstractControl: T): void {
if (abstractControl[EmpoweredFormControl.EMPOWER_KEY]) {
delete abstractControl[EmpoweredFormControl.EMPOWER_KEY];
}
}
private constructor(readonly abstractControl: T) {
this.empowerAbstractControl(this.abstractControl);
}
destroy() {
this.statusChangeHandlers = null;
EmpoweredFormControl.destroyEmpoweredControl(this.abstractControl);
}
registerStatusChange(fn: StatuChange): void {
this.statusChangeHandlers.push(fn);
}
get empoweredStatusChange(): Observable<EmpoweredStatus> {
return this.empoweredStatusSubject.asObservable();
}
private change(property: string, previousValue: any, currentValue: any) {
this.statusChangeHandlers.forEach(handler => {
handler(property, previousValue, currentValue);
});
}
private empowerAbstractControl(abstractControl: T) {
['touched', 'pristine'].forEach(property => {
for (let baseProperty of ['_' + property, property]) {
let propertyValue: any = abstractControl[baseProperty];
if (propertyValue !== undefined) {
Object.defineProperty(abstractControl, baseProperty, {
get: () => propertyValue,
set: (value: any) => {
let previousValue = propertyValue;
propertyValue = value;
this.change(property, previousValue, propertyValue);
}
});
break;
}
}
});
this.registerStatusChange((property: string, previousValue: any, value: any) => {
this.empoweredStatusSubject.next({
property,
value,
previousValue
});
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment