useFormDirty
Returns whether a FormGroup is dirty (has been modified) as a signal. The signal updates reactively whenever the form's dirty state changes.
Usage
typescript
import { useFormDirty } from 'ng-reactive-utils';
@Component({
template: `
<form [formGroup]="form">
<input formControlName="title" />
<textarea formControlName="content"></textarea>
@if (isDirty()) {
<div class="unsaved-warning">
You have unsaved changes
<button (click)="resetForm()">Discard</button>
</div>
}
<button [disabled]="!isDirty()">Save Changes</button>
</form>
`,
})
class EditorComponent {
form = new FormGroup({
title: new FormControl(''),
content: new FormControl(''),
});
isDirty = useFormDirty(this.form);
resetForm() {
this.form.reset();
}
// Use with canDeactivate guard
canDeactivate(): boolean {
return !this.isDirty() || confirm('Discard unsaved changes?');
}
}Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
form | FormGroup | required | The FormGroup to check dirty state for |
Returns
Signal<boolean> - A readonly signal containing the dirty state (true if modified)
Notes
- Uses
toSignalwithform.valueChangesobservable - Returns
truewhen any control value has been changed by the user - Returns
falsewhen form is pristine (unchanged) - Useful for "unsaved changes" warnings and save button states
Source
ts
import { Signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { FormGroup } from '@angular/forms';
import { map } from 'rxjs';
/**
* Returns whether a FormGroup is dirty (has been modified) as a signal.
* The signal updates reactively whenever the form's dirty state changes.
*
* @param form - The FormGroup to check dirty state for
* @returns A signal containing the dirty state (true if modified)
*
* @example
* ```typescript
* @Component({
* template: `
* <form [formGroup]="form">
* <input formControlName="name" />
* @if (isDirty()) {
* <span>You have unsaved changes</span>
* }
* </form>
* `
* })
* class MyComponent {
* form = new FormGroup({
* name: new FormControl('')
* });
* isDirty = useFormDirty(this.form);
* }
* ```
*/
export const useFormDirty = (form: FormGroup): Signal<boolean> => {
return toSignal(form.valueChanges.pipe(map(() => form.dirty)), {
initialValue: form.dirty,
}) as Signal<boolean>;
};