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 {