From c2e0be7600a0e3ad0e6a00db7e60020349f2897f Mon Sep 17 00:00:00 2001 From: kirjs Date: Fri, 16 Jan 2026 11:09:38 -0500 Subject: [PATCH] refactor(forms): add events observable with ControlEvents - Emit ValueChangeEvent, StatusChangeEvent on changes - Emit TouchedChangeEvent, PristineChangeEvent on status changes - Emit FormResetEvent on reset() - Add emitControlEvent helper method --- .../signal_form_control.ts | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/forms/signals/compat/src/signal_form_control/signal_form_control.ts b/packages/forms/signals/compat/src/signal_form_control/signal_form_control.ts index 4ac1eb9344e..16051faef98 100644 --- a/packages/forms/signals/compat/src/signal_form_control/signal_form_control.ts +++ b/packages/forms/signals/compat/src/signal_form_control/signal_form_control.ts @@ -7,7 +7,17 @@ */ import {EventEmitter, inject, Injector, signal, WritableSignal, effect} from '@angular/core'; -import {AbstractControl, FormControlStatus, FormControlState} from '@angular/forms'; +import { + AbstractControl, + ControlEvent, + FormControlStatus, + FormControlState, + PristineChangeEvent, + StatusChangeEvent, + TouchedChangeEvent, + ValueChangeEvent, + FormResetEvent, +} from '@angular/forms'; import {compatForm} from '../api/compat_form'; import {signalErrorsToValidationErrors} from '../../../src/api/rules'; @@ -57,6 +67,7 @@ export class SignalFormControl extends AbstractControl { () => { const value = this.sourceValue(); this.valueChanges.emit(value); + this.emitControlEvent(new ValueChangeEvent(value, this)); }, {injector}, ); @@ -66,9 +77,32 @@ export class SignalFormControl extends AbstractControl { () => { const status = this.status; this.statusChanges.emit(status); + this.emitControlEvent(new StatusChangeEvent(status, this)); }, {injector}, ); + + // Touched changes effect + effect( + () => { + const isTouched = this.fieldState.touched(); + this.emitControlEvent(new TouchedChangeEvent(isTouched, this)); + }, + {injector}, + ); + + // Dirty changes effect + effect( + () => { + const isDirty = this.fieldState.dirty(); + this.emitControlEvent(new PristineChangeEvent(!isDirty, this)); + }, + {injector}, + ); + } + + private emitControlEvent(event: ControlEvent): void { + (this as any)._events.next(event); } override setValue(value: any): void { @@ -83,7 +117,7 @@ export class SignalFormControl extends AbstractControl { return this.value; } - override reset(value?: T | FormControlState): void { + override reset(value?: T | FormControlState, options?: {emitEvent?: boolean}): void { if (isFormControlState(value)) { value = value.value; } @@ -94,6 +128,10 @@ export class SignalFormControl extends AbstractControl { if (value !== undefined) { this.sourceValue.set(value); } + + if (options?.emitEvent !== false) { + this.emitControlEvent(new FormResetEvent(this)); + } } override get status(): FormControlStatus {