@@ -16,13 +16,14 @@ import {
16
16
ViewChild ,
17
17
ContentChild ,
18
18
Injectable ,
19
- AfterViewInit
19
+ AfterViewInit ,
20
+ Injector
20
21
} from '@angular/core' ;
21
- import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ;
22
+ import { ControlValueAccessor , NG_VALUE_ACCESSOR , NgControl , AbstractControl } from '@angular/forms' ;
22
23
import { HAMMER_GESTURE_CONFIG , HammerGestureConfig } from '@angular/platform-browser' ;
23
24
import { IgxIconModule } from '../icon/index' ;
24
25
import { IgxInputGroupModule , IgxInputGroupComponent } from '../input-group/input-group.component' ;
25
- import { IgxInputDirective } from '../directives/input/input.directive' ;
26
+ import { IgxInputDirective , IgxInputState } from '../directives/input/input.directive' ;
26
27
import {
27
28
IgxAmPmItemDirective ,
28
29
IgxHourItemDirective ,
@@ -32,7 +33,7 @@ import {
32
33
IgxTimePickerTemplateDirective ,
33
34
IgxTimePickerActionsDirective
34
35
} from './time-picker.directives' ;
35
- import { Subject , fromEvent , interval , animationFrameScheduler } from 'rxjs' ;
36
+ import { Subject , fromEvent , interval , animationFrameScheduler , Subscription } from 'rxjs' ;
36
37
import { EditorProvider } from '../core/edit-provider' ;
37
38
import { IgxTimePickerBase , IGX_TIME_PICKER_COMPONENT } from './time-picker.common' ;
38
39
import { AbsoluteScrollStrategy } from '../services/overlay/scroll' ;
@@ -70,6 +71,8 @@ export interface IgxTimePickerValidationFailedEventArgs extends IBaseEventArgs {
70
71
setThroughUI : boolean ;
71
72
}
72
73
74
+ const noop = ( ) => { } ;
75
+
73
76
@Component ( {
74
77
providers : [
75
78
{
@@ -548,6 +551,9 @@ export class IgxTimePickerComponent implements
548
551
@ViewChild ( 'input' , { read : ElementRef } )
549
552
private input : ElementRef ;
550
553
554
+ @ViewChild ( IgxInputDirective , { read : IgxInputDirective } )
555
+ private _inputDirective : IgxInputDirective ;
556
+
551
557
/**
552
558
* @hidden
553
559
*/
@@ -643,6 +649,7 @@ export class IgxTimePickerComponent implements
643
649
644
650
private _dateFromModel : Date ;
645
651
private _destroy$ = new Subject < boolean > ( ) ;
652
+ private _statusChanges$ : Subscription ;
646
653
private _dropDownOverlaySettings : OverlaySettings ;
647
654
private _dialogOverlaySettings : OverlaySettings ;
648
655
@@ -658,9 +665,38 @@ export class IgxTimePickerComponent implements
658
665
private _minutesPos = new Set ( ) ;
659
666
private _secondsPos = new Set ( ) ;
660
667
private _amPmPos = new Set ( ) ;
668
+ private _ngControl : NgControl = null ;
669
+
670
+ //#region ControlValueAccessor
671
+
672
+ private _onChangeCallback : ( _ : Date ) => void = noop ;
673
+ private _onTouchedCallback : ( ) => void = noop ;
674
+
675
+ /** @hidden @internal */
676
+ public writeValue ( value : Date ) {
677
+ // use this flag to make sure that min/maxValue are checked (in _convertMinMaxValue() method)
678
+ // against the real value when initializing the component and value is bound via ngModel
679
+ this . _dateFromModel = value ;
680
+
681
+ this . _value = value ;
682
+
683
+ if ( this . mode === InteractionMode . DropDown ) {
684
+ this . displayValue = this . _formatTime ( this . value , this . format ) ;
685
+ }
686
+ }
687
+
688
+ /** @hidden @internal */
689
+ public registerOnChange ( fn : ( _ : Date ) => void ) { this . _onChangeCallback = fn ; }
690
+
691
+ /** @hidden @internal */
692
+ public registerOnTouched ( fn : ( ) => void ) { this . _onTouchedCallback = fn ; }
693
+
694
+ /** @hidden @internal */
695
+ public setDisabledState ( isDisabled : boolean ) : void { this . disabled = isDisabled ; }
696
+
697
+ //#endregion
698
+
661
699
662
- private _onTouchedCallback : ( ) => void = ( ) => { } ;
663
- private _onChangeCallback : ( _ : Date ) => void = ( ) => { } ;
664
700
665
701
private trimMask ( ) : void {
666
702
this . mask = this . mask . slice ( this . mask . indexOf ( ':' ) + 1 , this . mask . length ) ;
@@ -851,6 +887,7 @@ export class IgxTimePickerComponent implements
851
887
positionStrategy : new AutoPositionStrategy ( )
852
888
} ;
853
889
this . _dialogOverlaySettings = { } ;
890
+ this . _ngControl = this . _injector . get < NgControl > ( NgControl , null ) ;
854
891
}
855
892
856
893
/**
@@ -908,6 +945,12 @@ export class IgxTimePickerComponent implements
908
945
} ) ;
909
946
910
947
this . determineCursorPos ( ) ;
948
+
949
+ if ( this . _ngControl ) {
950
+ this . _statusChanges$ = this . _ngControl . statusChanges . subscribe ( this . onStatusChanged . bind ( this ) ) ;
951
+ }
952
+
953
+ this . manageRequiredAsterisk ( ) ;
911
954
}
912
955
}
913
956
@@ -937,6 +980,8 @@ export class IgxTimePickerComponent implements
937
980
this . openDialog ( this . getInputGroupElement ( ) ) ;
938
981
}
939
982
983
+ constructor ( private _injector : Injector ) { }
984
+
940
985
private determineCursorPos ( ) : void {
941
986
this . clearCursorPos ( ) ;
942
987
for ( const char of this . format ) {
@@ -1493,6 +1538,25 @@ export class IgxTimePickerComponent implements
1493
1538
}
1494
1539
}
1495
1540
1541
+ protected onStatusChanged ( ) {
1542
+ if ( ( this . _ngControl . control . touched || this . _ngControl . control . dirty ) &&
1543
+ ( this . _ngControl . control . validator || this . _ngControl . control . asyncValidator ) ) {
1544
+ if ( this . group . isFocused ) {
1545
+ this . _inputDirective . valid = this . _ngControl . valid ? IgxInputState . VALID : IgxInputState . INVALID ;
1546
+ } else {
1547
+ this . _inputDirective . valid = this . _ngControl . valid ? IgxInputState . INITIAL : IgxInputState . INVALID ;
1548
+ }
1549
+ }
1550
+ this . manageRequiredAsterisk ( ) ;
1551
+ }
1552
+
1553
+ protected manageRequiredAsterisk ( ) : void {
1554
+ if ( this . _ngControl && this . _ngControl . control . validator ) {
1555
+ // Run the validation with empty object to check if required is enabled.
1556
+ const error = this . _ngControl . control . validator ( { } as AbstractControl ) ;
1557
+ this . group . isRequired = error && error . required ;
1558
+ }
1559
+ }
1496
1560
/**
1497
1561
* @hidden
1498
1562
*/
@@ -1507,35 +1571,6 @@ export class IgxTimePickerComponent implements
1507
1571
return this . group ? this . group . element . nativeElement : null ;
1508
1572
}
1509
1573
1510
- /**
1511
- * @hidden
1512
- */
1513
- public writeValue ( value : Date ) {
1514
- // use this flag to make sure that min/maxValue are checked (in _convertMinMaxValue() method)
1515
- // against the real value when initializing the component and value is bound via ngModel
1516
- this . _dateFromModel = value ;
1517
-
1518
- this . value = value ;
1519
-
1520
- if ( this . mode === InteractionMode . DropDown ) {
1521
- this . displayValue = this . _formatTime ( this . value , this . format ) ;
1522
- }
1523
- }
1524
-
1525
- /**
1526
- * @hidden
1527
- */
1528
- public registerOnChange ( fn : ( _ : Date ) => void ) { this . _onChangeCallback = fn ; }
1529
-
1530
- /**
1531
- *@hidden
1532
- */
1533
- public setDisabledState ( isDisabled : boolean ) : void { this . disabled = isDisabled ; }
1534
-
1535
- /**
1536
- * @hidden
1537
- */
1538
- public registerOnTouched ( fn : ( ) => void ) { this . _onTouchedCallback = fn ; }
1539
1574
1540
1575
/**
1541
1576
* opens the dialog.
@@ -1982,6 +2017,23 @@ export class IgxTimePickerComponent implements
1982
2017
this . onValidationFailed . emit ( args ) ;
1983
2018
}
1984
2019
}
2020
+
2021
+ this . _onTouchedCallback ( ) ;
2022
+ if ( this . toggleRef . collapsed ) {
2023
+ if ( this . _ngControl && ! this . _ngControl . valid ) {
2024
+ this . _inputDirective . valid = IgxInputState . INVALID ;
2025
+ } else {
2026
+ this . _inputDirective . valid = IgxInputState . INITIAL ;
2027
+ }
2028
+ }
2029
+ }
2030
+
2031
+ public mouseDown ( event : MouseEvent ) : void {
2032
+ // if the click is not on the input but in input group
2033
+ // e.g. on prefix or suffix, prevent default and this way prevent blur
2034
+ if ( event . target !== this . getEditElement ( ) ) {
2035
+ event . preventDefault ( ) ;
2036
+ }
1985
2037
}
1986
2038
1987
2039
/**
0 commit comments