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