useControlTouched
Returns whether an AbstractControl has been touched (interacted with) as a signal. The signal updates reactively whenever the control's touched state changes. Works with FormControl, FormGroup, and FormArray.
Usage
typescript
import { useControlTouched } from 'ng-reactive-utils';
@Component({
template: `
<input [formControl]="emailControl" placeholder="Email" />
@if (isTouched() && emailControl.invalid) {
<span class="error">Please enter a valid email</span>
}
`,
})
class EmailInputComponent {
emailControl = new FormControl('', [Validators.required, Validators.email]);
isTouched = useControlTouched(this.emailControl);
}Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
control | AbstractControl | required | The control to check touched state for |
Returns
Signal<boolean> - A readonly signal containing the touched state (true if interacted with)
Notes
- Works with FormControl, FormGroup, and FormArray
- Uses
control.events(Angular's unified event stream) filtered toTouchedChangeEvent— notstatusChanges, which does not emit on touched-state changes - Returns
truewhenmarkAsTouched()is called or the control loses focus (blur) - Useful for showing validation errors only after user interaction
Source
ts
import { Signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { AbstractControl, TouchedChangeEvent } from '@angular/forms';
import { filter, map } from 'rxjs';
/**
* Returns whether an AbstractControl has been touched (interacted with) as a signal.
* The signal updates reactively whenever the control's touched state changes,
* including when markAsTouched() or markAsUntouched() are called directly.
* Works with FormControl, FormGroup, and FormArray.
*
* @param control - The AbstractControl to check touched state for
* @returns A signal containing the touched state (true if interacted with)
*
* @example
* ```typescript
* @Component({
* template: `
* <input [formControl]="emailControl" />
* @if (isTouched() && emailControl.invalid) {
* <span>Please enter a valid email</span>
* }
* `
* })
* class MyComponent {
* emailControl = new FormControl('', Validators.email);
* isTouched = useControlTouched(this.emailControl);
* }
* ```
*/
export const useControlTouched = (control: AbstractControl): Signal<boolean> => {
return toSignal(
control.events.pipe(
filter((event): event is TouchedChangeEvent => event instanceof TouchedChangeEvent),
map((event) => event.touched),
),
{ initialValue: control.touched },
) as Signal<boolean>;
};