11import { Component , DestroyRef , inject , TemplateRef , ViewChild , OnInit } from '@angular/core' ;
2- import { FormsModule } from '@angular/forms' ;
2+ import { FormsModule , ReactiveFormsModule , UntypedFormBuilder , Validators } from '@angular/forms' ;
33import {
44 IgxTimePickerComponent ,
5- IgxInputDirective ,
6- AutoPositionStrategy ,
7- OverlaySettings ,
85 DatePart ,
96 IgxHintDirective ,
107 IgxButtonDirective ,
@@ -32,6 +29,7 @@ import {
3229 imports : [
3330 IgxTimePickerComponent ,
3431 FormsModule ,
32+ ReactiveFormsModule ,
3533 IgxHintDirective ,
3634 IgxButtonDirective ,
3735 IgxPickerActionsDirective ,
@@ -49,9 +47,6 @@ export class TimePickerSampleComponent implements OnInit {
4947 @ViewChild ( 'tp' , { read : IgxTimePickerComponent , static : true } )
5048 public tp : IgxTimePickerComponent ;
5149
52- @ViewChild ( 'target' )
53- public target : IgxInputDirective ;
54-
5550 @ViewChild ( 'customControls' , { static : true } )
5651 public customControlsTemplate ! : TemplateRef < any > ;
5752
@@ -61,7 +56,6 @@ export class TimePickerSampleComponent implements OnInit {
6156 public hasHint = false ;
6257
6358 public itemsDelta = { hours : 1 , minutes : 15 , seconds : 20 } ;
64- public format = 'hh:mm:ss:SS a' ;
6559 public spinLoop = true ;
6660 public datePart = DatePart . Hours ;
6761
@@ -72,14 +66,6 @@ export class TimePickerSampleComponent implements OnInit {
7266 public val = '08:30:00' ;
7367 public today = new Date ( Date . now ( ) ) ;
7468
75- public isRequired = true ;
76-
77- public myOverlaySettings : OverlaySettings = {
78- modal : false ,
79- closeOnOutsideClick : true ,
80- positionStrategy : new AutoPositionStrategy ( )
81- } ;
82-
8369 public panelConfig : PropertyPanelConfig = {
8470 size : {
8571 control : {
@@ -105,6 +91,12 @@ export class TimePickerSampleComponent implements OnInit {
10591 defaultValue : 'box'
10692 }
10793 } ,
94+ required : {
95+ control : {
96+ type : 'boolean' ,
97+ defaultValue : false
98+ }
99+ } ,
108100 readonly : {
109101 control : {
110102 type : 'boolean' ,
@@ -142,17 +134,30 @@ export class TimePickerSampleComponent implements OnInit {
142134 }
143135 }
144136
145- public properties : Properties ;
137+ private fb = inject ( UntypedFormBuilder ) ;
146138 private propertyChangeService = inject ( PropertyChangeService ) ;
147139 private destroyRef = inject ( DestroyRef ) ;
148140
141+ public properties : Properties = Object . fromEntries (
142+ Object . keys ( this . panelConfig ) . map ( ( key ) => {
143+ const control = this . panelConfig [ key ] ?. control ;
144+ return [ key , control ?. defaultValue ] ;
145+ } )
146+ ) as Properties ;
147+
148+ // FormControl owns the time picker value
149+ public reactiveForm = this . fb . group ( {
150+ timePicker : [ null ] ,
151+ } ) ;
152+
149153 constructor ( ) {
150154 this . propertyChangeService . setPanelConfig ( this . panelConfig ) ;
151155
152156 const propertyChange =
153157 this . propertyChangeService . propertyChanges . subscribe (
154158 ( properties ) => {
155159 this . properties = properties ;
160+ this . syncFormControlFromProperties ( ) ;
156161 }
157162 ) ;
158163
@@ -165,11 +170,55 @@ export class TimePickerSampleComponent implements OnInit {
165170 ) ;
166171 }
167172
168- public change ( ) {
169- this . isRequired = ! this . isRequired ;
170- }
173+ /**
174+ * Syncs the reactive form control with the properties panel:
175+ * - programmatic value updates
176+ * - required validator
177+ * - disabled state
178+ *
179+ * All done in a way that does NOT mark the control dirty/touched.
180+ */
181+ private syncFormControlFromProperties ( ) : void {
182+ const control = this . reactiveForm . get ( 'timePicker' ) ;
183+ if ( ! control ) {
184+ return ;
185+ }
186+
187+ // 1) Programmatic value update (from properties.value)
188+ // This does NOT mark the control dirty/touched.
189+ if ( 'value' in this . properties ) {
190+ const newValue = this . properties . value ?? null ;
191+ const currentValue = control . value ;
192+
193+ // Shallow equality check to avoid unnecessary writes
194+ const sameValue =
195+ ( newValue === currentValue ) ||
196+ ( newValue instanceof Date &&
197+ currentValue instanceof Date &&
198+ newValue . getTime ( ) === currentValue . getTime ( ) ) ;
199+
200+ if ( ! sameValue ) {
201+ control . setValue ( newValue , { emitEvent : false } ) ;
202+ }
203+ }
171204
172- public valueChanged ( event ) {
205+ // 2) Required validator - set without triggering validation
206+ const currentValidators = control . validator ;
207+ const newValidators = this . properties ?. required ? Validators . required : null ;
208+
209+ // Only update validators if they actually changed
210+ if ( currentValidators !== newValidators ) {
211+ control . setValidators ( newValidators ) ;
212+ // Don't call updateValueAndValidity - let natural form lifecycle handle validation
213+ }
214+
215+ // 3) Disabled state
216+ if ( this . properties ?. disabled ) {
217+ control . disable ( { emitEvent : false } ) ;
218+ } else {
219+ control . enable ( { emitEvent : false } ) ;
220+ }
221+ } public valueChanged ( event ) {
173222 console . log ( event ) ;
174223 }
175224
0 commit comments