@@ -141,8 +141,8 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
141141 if ( value ) {
142142 this . _format = value ;
143143 }
144- const mask = this . inputFormat ?. replace ( / \w / g , '0' ) ;
145- this . mask = value . indexOf ( 'tt' ) !== - 1 ? mask . substring ( 0 , mask . length - 2 ) + 'LL' : mask ;
144+ const mask = this . inputFormat ?. replace ( new RegExp ( / (? = [ ^ t ] ) [ \w ] / , 'g' ) , '0' ) ;
145+ this . mask = mask . indexOf ( 'tt' ) !== - 1 ? mask . replace ( new RegExp ( 'tt' , 'g' ) , 'LL' ) : mask ;
146146 }
147147
148148 public get inputFormat ( ) : string {
@@ -160,9 +160,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
160160 public set value ( value : Date ) {
161161 this . _value = value ;
162162 this . onChangeCallback ( value ) ;
163- if ( value ) {
164- this . updateMask ( ) ;
165- }
163+ this . updateMask ( ) ;
166164 }
167165
168166 public get value ( ) {
@@ -219,6 +217,20 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
219217 }
220218 }
221219
220+ private get hasDateParts ( ) {
221+ return this . _inputDateParts . some (
222+ p => p . type === DatePart . Date
223+ || p . type === DatePart . Month
224+ || p . type === DatePart . Year ) ;
225+ }
226+
227+ private get hasTimeParts ( ) {
228+ return this . _inputDateParts . some (
229+ p => p . type === DatePart . Hours
230+ || p . type === DatePart . Minutes
231+ || p . type === DatePart . Seconds ) ;
232+ }
233+
222234 constructor (
223235 protected renderer : Renderer2 ,
224236 protected elementRef : ElementRef ,
@@ -241,9 +253,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
241253 this . renderer . setAttribute ( this . nativeElement , 'placeholder' , defPlaceholder ) ;
242254 }
243255 // TODO: fill in partial dates?
244- if ( this . value ) {
245- this . updateMask ( ) ;
246- }
256+ this . updateMask ( ) ;
247257 }
248258 }
249259
@@ -255,7 +265,6 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
255265 /** Clear the input element value. */
256266 public clear ( ) : void {
257267 this . updateValue ( null ) ;
258- this . inputValue = this . _isFocused ? this . emptyMask : '' ;
259268 }
260269
261270 /**
@@ -292,15 +301,22 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
292301
293302 /** @hidden @internal */
294303 public validate ( control : AbstractControl ) : ValidationErrors | null {
295- if ( this . minValue && ! this . valueInRange ( control . value ) ) {
304+ if ( ! this . inputIsComplete ( ) || ! control . value ) {
305+ return { 'value' : true } ;
306+ }
307+
308+ const maxValueAsDate = this . isDate ( this . maxValue ) ? this . maxValue : this . parseDate ( this . maxValue ) ;
309+ const minValueAsDate = this . isDate ( this . minValue ) ? this . minValue : this . parseDate ( this . minValue ) ;
310+ if ( minValueAsDate
311+ && DatePickerUtil . lessThanMinValue (
312+ control . value , minValueAsDate , this . hasTimeParts , this . hasDateParts ) ) {
296313 return { 'minValue' : true } ;
297314 }
298- if ( this . maxValue && ! this . valueInRange ( control . value ) ) {
315+ if ( maxValueAsDate
316+ && DatePickerUtil . greaterThanMaxValue (
317+ control . value , maxValueAsDate , this . hasTimeParts , this . hasDateParts ) ) {
299318 return { 'maxValue' : true } ;
300319 }
301- if ( ! this . inputIsComplete ( ) ) {
302- return { 'value' : true } ;
303- }
304320
305321 return null ;
306322 }
@@ -360,11 +376,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
360376 public onFocus ( ) : void {
361377 this . _isFocused = true ;
362378 this . onTouchCallback ( ) ;
363- if ( this . value ) {
364- this . updateMask ( ) ;
365- } else {
366- this . inputValue = this . emptyMask ;
367- }
379+ this . updateMask ( ) ;
368380 super . onFocus ( ) ;
369381 }
370382
@@ -373,24 +385,26 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
373385 this . _isFocused = false ;
374386 if ( ! this . inputIsComplete ( ) && this . inputValue !== this . emptyMask ) {
375387 this . updateValue ( this . parseDate ( this . inputValue ) ) ;
376- }
377- if ( ! this . isValidDate ( this . value ) ) {
378- this . inputValue = '' ;
379- return ;
388+ } else {
389+ this . updateMask ( ) ;
380390 }
381391
382- this . updateMask ( ) ;
383392 super . onBlur ( value ) ;
384393 }
385394
386395 /** @hidden @internal */
387396 public updateMask ( ) : void {
388397 if ( this . _isFocused ) {
398+ if ( ! this . value ) { return ; }
389399 // store the cursor position as it will be moved during masking
390400 const cursor = this . selectionEnd ;
391401 this . inputValue = this . getMaskedValue ( ) ;
392402 this . setSelectionRange ( cursor ) ;
393403 } else {
404+ if ( ! this . value || ! this . isValidDate ( this . value ) ) {
405+ this . inputValue = '' ;
406+ return ;
407+ }
394408 const format = this . displayFormat || this . inputFormat ;
395409 if ( format ) {
396410 this . inputValue = formatDate ( this . value , format . replace ( 'tt' , 'aa' ) , this . locale ) ;
@@ -405,19 +419,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
405419 let mask = this . emptyMask ;
406420 for ( const part of this . _inputDateParts ) {
407421 if ( part . type === DatePart . Literal ) { continue ; }
408- const partLength = part . format . length ;
409- let targetValue = this . getPartValue ( part . type , partLength ) ;
410- if ( part . type === DatePart . Month ) {
411- targetValue = this . prependValue (
412- parseInt ( targetValue . replace ( new RegExp ( this . promptChar , 'g' ) , '0' ) , 10 ) + 1 , partLength , '0' ) ;
413- }
414- if ( part . type === DatePart . Hours && part . format . indexOf ( 'h' ) !== - 1 ) {
415- targetValue = this . prependValue ( this . toTwelveHourFormat ( targetValue ) , partLength , '0' ) ;
416- }
417- if ( part . type === DatePart . Year && partLength === 2 ) {
418- targetValue = this . prependValue ( parseInt ( targetValue . slice ( - 2 ) , 10 ) , partLength , '0' ) ;
419- }
420-
422+ const targetValue = this . getPartValue ( part , part . format . length ) ;
421423 mask = this . maskParser . replaceInMask ( mask , targetValue , this . maskOptions , part . start , part . end ) . value ;
422424 }
423425
@@ -432,23 +434,20 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
432434 if ( ! value ) { return false ; }
433435 const maxValueAsDate = this . isDate ( this . maxValue ) ? this . maxValue : this . parseDate ( this . maxValue ) ;
434436 const minValueAsDate = this . isDate ( this . minValue ) ? this . minValue : this . parseDate ( this . minValue ) ;
435- if ( minValueAsDate && value && this . compareDates ( value , minValueAsDate ) ) {
437+ if ( minValueAsDate
438+ && DatePickerUtil . lessThanMinValue (
439+ value , minValueAsDate , this . hasTimeParts , this . hasDateParts ) ) {
436440 return false ;
437- } else if ( maxValueAsDate && value && this . compareDates ( maxValueAsDate , value ) ) {
441+ }
442+ if ( maxValueAsDate
443+ && DatePickerUtil . greaterThanMaxValue (
444+ value , maxValueAsDate , this . hasTimeParts , this . hasDateParts ) ) {
438445 return false ;
439446 }
440447
441448 return true ;
442449 }
443450
444- private compareDates ( firstDate : Date , secondDate : Date ) {
445- const _firstDate = new Date ( firstDate . getTime ( ) ) ;
446- _firstDate . setHours ( 0 , 0 , 0 , 0 ) ;
447- const _secondDate = new Date ( secondDate . getTime ( ) ) ;
448- _secondDate . setHours ( 0 , 0 , 0 , 0 ) ;
449- return _firstDate . getTime ( ) < _secondDate . getTime ( ) ;
450- }
451-
452451 private spinValue ( datePart : DatePart , delta : number ) : Date {
453452 if ( ! this . value || ! this . isValidDate ( this . value ) ) { return null ; }
454453 const newDate = new Date ( this . value . getTime ( ) ) ;
@@ -507,20 +506,32 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
507506 return hour ;
508507 }
509508
510- private getPartValue ( datePart : DatePart , partLength : number ) : string {
509+ private getPartValue ( datePartInfo : DatePartInfo , partLength : number ) : string {
511510 let maskedValue ;
511+ const datePart = datePartInfo . type ;
512512 switch ( datePart ) {
513513 case DatePart . Date :
514514 maskedValue = this . value . getDate ( ) ;
515515 break ;
516516 case DatePart . Month :
517- maskedValue = this . value . getMonth ( ) ;
517+ // months are zero based
518+ maskedValue = this . value . getMonth ( ) + 1 ;
518519 break ;
519520 case DatePart . Year :
520- maskedValue = this . value . getFullYear ( ) ;
521+ if ( partLength === 2 ) {
522+ maskedValue = this . prependValue (
523+ parseInt ( this . value . getFullYear ( ) . toString ( ) . slice ( - 2 ) , 10 ) , partLength , '0' ) ;
524+ } else {
525+ maskedValue = this . value . getFullYear ( ) ;
526+ }
521527 break ;
522528 case DatePart . Hours :
523- maskedValue = this . value . getHours ( ) ;
529+ if ( datePartInfo . format . indexOf ( 'h' ) !== - 1 ) {
530+ maskedValue = this . prependValue (
531+ this . toTwelveHourFormat ( this . value . getHours ( ) . toString ( ) ) , partLength , '0' ) ;
532+ } else {
533+ maskedValue = this . value . getHours ( ) ;
534+ }
524535 break ;
525536 case DatePart . Minutes :
526537 maskedValue = this . value . getMinutes ( ) ;
@@ -533,7 +544,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
533544 break ;
534545 }
535546
536- if ( datePart !== DatePart . AmPm ) {
547+ if ( datePartInfo . type !== DatePart . AmPm ) {
537548 return this . prependValue ( maskedValue , partLength , '0' ) ;
538549 }
539550
0 commit comments