@@ -447,6 +447,11 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
447
447
448
448
. constant ( 'datepickerPopupConfig' , {
449
449
datepickerPopup : 'yyyy-MM-dd' ,
450
+ html5Types : {
451
+ date : 'yyyy-MM-dd' ,
452
+ 'datetime-local' : 'yyyy-MM-ddTHH:mm:ss.sss'
453
+ // TODO: Add other formats/type support
454
+ } ,
450
455
currentText : 'Today' ,
451
456
clearText : 'Clear' ,
452
457
closeText : 'Done' ,
@@ -479,16 +484,34 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
479
484
return scope [ key + 'Text' ] || datepickerPopupConfig [ key + 'Text' ] ;
480
485
} ;
481
486
482
- dateFormat = attrs . datepickerPopup || datepickerPopupConfig . datepickerPopup ;
483
- attrs . $observe ( 'datepickerPopup' , function ( value , oldValue ) {
484
- var newDateFormat = value || datepickerPopupConfig . datepickerPopup ;
485
- // Invalidate the $modelValue to ensure that formatters re-run
486
- // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
487
- if ( newDateFormat !== dateFormat ) {
488
- dateFormat = newDateFormat ;
489
- ngModel . $modelValue = null ;
490
- }
491
- } ) ;
487
+ var isHtml5DateInput = false ;
488
+ if ( datepickerPopupConfig . html5Types [ attrs . type ] ) {
489
+ dateFormat = datepickerPopupConfig . html5Types [ attrs . type ] ;
490
+ isHtml5DateInput = true ;
491
+ } else {
492
+ dateFormat = attrs . datepickerPopup || datepickerPopupConfig . datepickerPopup ;
493
+ attrs . $observe ( 'datepickerPopup' , function ( value , oldValue ) {
494
+ var newDateFormat = value || datepickerPopupConfig . datepickerPopup ;
495
+ // Invalidate the $modelValue to ensure that formatters re-run
496
+ // FIXME: Refactor when PR is merged: https://github.com/angular/angular.js/pull/10764
497
+ if ( newDateFormat !== dateFormat ) {
498
+ dateFormat = newDateFormat ;
499
+ ngModel . $modelValue = null ;
500
+
501
+ if ( ! dateFormat ) {
502
+ throw new Error ( 'datepickerPopup must have a date format specified.' ) ;
503
+ }
504
+ }
505
+ } ) ;
506
+ }
507
+
508
+ if ( ! dateFormat ) {
509
+ throw new Error ( 'datepickerPopup must have a date format specified.' ) ;
510
+ }
511
+
512
+ if ( isHtml5DateInput && attrs . datepickerPopup ) {
513
+ throw new Error ( 'HTML5 date input types do not support custom formats.' ) ;
514
+ }
492
515
493
516
// popup element used to display calendar
494
517
var popupEl = angular . element ( '<div datepicker-popup-wrap><div datepicker></div></div>' ) ;
@@ -547,8 +570,6 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
547
570
datepickerEl . attr ( 'custom-class' , 'customClass({ date: date, mode: mode })' ) ;
548
571
}
549
572
550
- // Internal API to maintain the correct ng-invalid-[key] class
551
- ngModel . $$parserName = 'date' ;
552
573
function parseDate ( viewValue ) {
553
574
if ( angular . isNumber ( viewValue ) ) {
554
575
// presumably timestamp to date object
@@ -560,7 +581,7 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
560
581
} else if ( angular . isDate ( viewValue ) && ! isNaN ( viewValue ) ) {
561
582
return viewValue ;
562
583
} else if ( angular . isString ( viewValue ) ) {
563
- var date = dateParser . parse ( viewValue , dateFormat ) || new Date ( viewValue ) ;
584
+ var date = dateParser . parse ( viewValue , dateFormat , scope . date ) || new Date ( viewValue ) ;
564
585
if ( isNaN ( date ) ) {
565
586
return undefined ;
566
587
} else {
@@ -588,24 +609,31 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
588
609
}
589
610
}
590
611
591
- ngModel . $validators . date = validator ;
592
- ngModel . $parsers . unshift ( parseDate ) ;
593
-
594
- ngModel . $formatters . push ( function ( value ) {
595
- scope . date = value ;
596
- return ngModel . $isEmpty ( value ) ? value : dateFilter ( value , dateFormat ) ;
597
- } ) ;
612
+ if ( ! isHtml5DateInput ) {
613
+ // Internal API to maintain the correct ng-invalid-[key] class
614
+ ngModel . $$parserName = 'date' ;
615
+ ngModel . $validators . date = validator ;
616
+ ngModel . $parsers . unshift ( parseDate ) ;
617
+ ngModel . $formatters . push ( function ( value ) {
618
+ scope . date = value ;
619
+ return ngModel . $isEmpty ( value ) ? value : dateFilter ( value , dateFormat ) ;
620
+ } ) ;
621
+ }
622
+ else {
623
+ ngModel . $formatters . push ( function ( value ) {
624
+ scope . date = value ;
625
+ return value ;
626
+ } ) ;
627
+ }
598
628
599
629
// Inner change
600
630
scope . dateSelection = function ( dt ) {
601
631
if ( angular . isDefined ( dt ) ) {
602
632
scope . date = dt ;
603
633
}
604
- if ( dateFormat ) {
605
- var date = scope . date ? dateFilter ( scope . date , dateFormat ) : '' ;
606
- element . val ( date ) ;
607
- }
608
- ngModel . $setViewValue ( scope . date ) ;
634
+ var date = scope . date ? dateFilter ( scope . date , dateFormat ) : '' ;
635
+ element . val ( date ) ;
636
+ ngModel . $setViewValue ( date ) ;
609
637
610
638
if ( closeOnDateSelection ) {
611
639
scope . isOpen = false ;
@@ -615,7 +643,7 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
615
643
616
644
// Detect changes in the view from the text box
617
645
ngModel . $viewChangeListeners . push ( function ( ) {
618
- scope . date = ngModel . $viewValue ;
646
+ scope . date = dateParser . parse ( ngModel . $viewValue , dateFormat , scope . date ) || new Date ( ngModel . $viewValue ) ;
619
647
} ) ;
620
648
621
649
var documentClickBind = function ( event ) {
0 commit comments