@@ -161,7 +161,7 @@ export class DatePickerSampleComponent {
161161 type : 'text'
162162 }
163163 }
164- }
164+ } ;
165165
166166 public properties : Properties = Object . fromEntries (
167167 Object . keys ( this . panelConfig ) . map ( ( key ) => {
@@ -170,8 +170,9 @@ export class DatePickerSampleComponent {
170170 } )
171171 ) as Properties ;
172172
173+ // FormControl owns the date picker value
173174 public reactiveForm = this . fb . group ( {
174- datePicker : [ this . properties ?. value || '' ] ,
175+ datePicker : [ null ] ,
175176 } ) ;
176177
177178 constructor ( ) {
@@ -181,21 +182,56 @@ export class DatePickerSampleComponent {
181182 this . propertyChangeService . propertyChanges . subscribe (
182183 ( properties ) => {
183184 this . properties = properties ;
184- this . reactiveForm . patchValue ( {
185- datePicker : properties ?. value || ''
186- } ) ;
187- this . updateRequiredValidator ( ) ;
185+ this . syncFormControlFromProperties ( ) ;
188186 }
189187 ) ;
190188
191189 this . destroyRef . onDestroy ( ( ) => propertyChange . unsubscribe ( ) ) ;
192190 }
193191
194- private updateRequiredValidator ( ) : void {
192+ /**
193+ * Syncs the reactive form control with the properties panel:
194+ * - programmatic value updates
195+ * - required validator
196+ * - disabled state
197+ *
198+ * All done in a way that does NOT mark the control dirty/touched.
199+ */
200+ private syncFormControlFromProperties ( ) : void {
195201 const control = this . reactiveForm . get ( 'datePicker' ) ;
196- if ( control ) {
197- control . setValidators ( this . properties ?. required ? Validators . required : null ) ;
198- control . updateValueAndValidity ( ) ;
202+ if ( ! control ) {
203+ return ;
204+ }
205+
206+ // 1) Programmatic value update (from properties.value)
207+ // This does NOT mark the control dirty/touched.
208+ if ( 'value' in this . properties ) {
209+ const newValue = this . properties . value ?? null ;
210+ const currentValue = control . value ;
211+
212+ // Shallow equality check to avoid unnecessary writes
213+ const sameValue =
214+ ( newValue === currentValue ) ||
215+ ( newValue instanceof Date &&
216+ currentValue instanceof Date &&
217+ newValue . getTime ( ) === currentValue . getTime ( ) ) ;
218+
219+ if ( ! sameValue ) {
220+ control . setValue ( newValue , { emitEvent : false } ) ;
221+ }
222+ }
223+
224+ // 2) Required validator
225+ control . setValidators ( this . properties ?. required ? Validators . required : null ) ;
226+ // This will trigger statusChanges, but control is still pristine/untouched,
227+ // so IgxDatePicker will keep the visual state INITIAL until user interaction.
228+ control . updateValueAndValidity ( ) ;
229+
230+ // 3) Disabled state
231+ if ( this . properties ?. disabled ) {
232+ control . disable ( { emitEvent : false } ) ;
233+ } else {
234+ control . enable ( { emitEvent : false } ) ;
199235 }
200236 }
201237
@@ -206,7 +242,7 @@ export class DatePickerSampleComponent {
206242 : PickerInteractionMode . Dialog ;
207243 }
208244
209- protected selectToday ( picker ) {
245+ protected selectToday ( picker : { value : Date ; hide : ( ) => void } ) {
210246 picker . value = new Date ( ) ;
211247 picker . hide ( ) ;
212248 }
0 commit comments