diff --git a/CHANGELOG.md b/CHANGELOG.md
index bdf3f1d6..e4c0f859 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
# Changelog
All notable changes to this project will be documented in this file.
+# [22.1.0] (2026-09-21)
+
+### Bug Fixes
+- Support initial values and validator updates when the picker is used with Angular Signal Forms (follow-up to [#659](https://github.com/vlio20/angular-datepicker/issues/659)).
+
# [22.0.0] (2026-09-19)
### Improvements
diff --git a/projects/ng2-date-picker/package.json b/projects/ng2-date-picker/package.json
index b547e4ba..87da06aa 100644
--- a/projects/ng2-date-picker/package.json
+++ b/projects/ng2-date-picker/package.json
@@ -1,6 +1,6 @@
{
"name": "ng2-date-picker",
- "version": "22.0.0",
+ "version": "22.1.0",
"author": "Vlad Ioffe",
"license": "MIT",
"repository": {
diff --git a/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.spec.ts b/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.spec.ts
index e43d01cb..d0a2043d 100644
--- a/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.spec.ts
+++ b/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.spec.ts
@@ -1,4 +1,6 @@
+import {Component, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
+import {form, FormField} from '@angular/forms/signals';
import {DatePickerComponent} from './date-picker.component';
import {DayTimeCalendarComponent} from '../day-time-calendar/day-time-calendar.component';
import {DayTimeCalendarService} from '../day-time-calendar/day-time-calendar.service';
@@ -14,6 +16,16 @@ import {UtilsService} from '../common/services/utils/utils.service';
import {By} from '@angular/platform-browser';
import {OverlayModule} from '@angular/cdk/overlay';
+@Component({
+ standalone: false,
+ template: ''
+})
+class SignalFormDatePickerHostComponent {
+ readonly config = {format: 'YYYY-MM-DD'};
+ readonly model = signal({date: '2026-09-21'});
+ readonly dateForm = form(this.model);
+}
+
describe('Component: DatePickerComponent', () => {
let component: DatePickerComponent;
let fixture: ComponentFixture;
@@ -26,8 +38,9 @@ describe('Component: DatePickerComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
- imports: [FormsModule, OverlayModule],
+ imports: [FormsModule, OverlayModule, FormField],
declarations: [
+ SignalFormDatePickerHostComponent,
DatePickerComponent,
DayTimeCalendarComponent,
DayCalendarComponent,
@@ -54,6 +67,17 @@ describe('Component: DatePickerComponent', () => {
expect(component).toBeTruthy();
});
+ it('should render an initial value when bound through Signal Forms', () => {
+ const signalFormFixture = TestBed.createComponent(SignalFormDatePickerHostComponent);
+
+ expect(() => signalFormFixture.detectChanges()).not.toThrow();
+
+ const datePicker = signalFormFixture.debugElement.query(By.directive(DatePickerComponent))
+ .componentInstance as DatePickerComponent;
+ expect(datePicker.selected[0].format('YYYY-MM-DD')).toBe('2026-09-21');
+ expect(signalFormFixture.componentInstance.model().date).toBe('2026-09-21');
+ });
+
it('should emit event goToCurrent when day calendar emit', () => {
setComponentMode('day');
component.showCalendars();
diff --git a/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.ts b/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.ts
index b6991f44..4564fc07 100644
--- a/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.ts
+++ b/projects/ng2-date-picker/src/lib/date-picker/date-picker.component.ts
@@ -119,6 +119,8 @@ export class DatePickerComponent implements OnChanges,
handleInnerElementClickUnlisteners: Function[] = [];
globalListenersUnlisteners: Function[] = [];
validateFn: DateValidator;
+ private isWritingValue = false;
+ private onValidatorChange: () => void;
api: IDpDayPickerApi = {
open: this.showCalendars.bind(this),
close: this.hideCalendar.bind(this),
@@ -157,7 +159,9 @@ export class DatePickerComponent implements OnChanges,
.convertFromDayjsArray(this.componentConfig.format, selected, ECalendarValue.StringArr))
.join(' | ');
const val = this.processOnChangeCallback(selected);
- this.onChangeCallback(val, false);
+ if (!this.isWritingValue) {
+ this.onChangeCallback(val, false);
+ }
this.onChange.emit(val);
}
@@ -212,12 +216,19 @@ export class DatePickerComponent implements OnChanges,
writeValue(value: CalendarValue): void {
this.inputValue = value;
- if (value || value === '') {
- this.selected = this.utilsService
- .convertToDayjsArray(value, this.componentConfig);
- this.init();
- } else {
- this.selected = [];
+ this.isWritingValue = true;
+ try {
+ this.componentConfig ??= this.dayPickerService.getConfig(this.config, this.mode);
+
+ if (value || value === '') {
+ this.selected = this.utilsService
+ .convertToDayjsArray(value, this.componentConfig);
+ this.init();
+ } else {
+ this.selected = [];
+ }
+ } finally {
+ this.isWritingValue = false;
}
this.cd.markForCheck();
@@ -237,6 +248,10 @@ export class DatePickerComponent implements OnChanges,
onTouchedCallback() {
}
+ registerOnValidatorChange(fn: () => void): void {
+ this.onValidatorChange = fn;
+ }
+
validate(formControl: UntypedFormControl): ValidationErrors {
return this.validateFn(formControl.value);
}
@@ -262,7 +277,7 @@ export class DatePickerComponent implements OnChanges,
maxTime: this.maxTime
}, this.componentConfig.format, this.mode);
- this.onChangeCallback(this.processOnChangeCallback(this.selected), false);
+ this.onValidatorChange?.();
}
ngOnInit(): void {