@@ -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>' ) ;
@@ -544,8 +567,6 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
544
567
datepickerEl . attr ( 'custom-class' , 'customClass({ date: date, mode: mode })' ) ;
545
568
}
546
569
547
- // Internal API to maintain the correct ng-invalid-[key] class
548
- ngModel . $$parserName = 'date' ;
549
570
function parseDate ( viewValue ) {
550
571
if ( angular . isNumber ( viewValue ) ) {
551
572
// presumably timestamp to date object
@@ -557,7 +578,7 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
557
578
} else if ( angular . isDate ( viewValue ) && ! isNaN ( viewValue ) ) {
558
579
return viewValue ;
559
580
} else if ( angular . isString ( viewValue ) ) {
560
- var date = dateParser . parse ( viewValue , dateFormat ) || new Date ( viewValue ) ;
581
+ var date = dateParser . parse ( viewValue , dateFormat , scope . date ) || new Date ( viewValue ) ;
561
582
if ( isNaN ( date ) ) {
562
583
return undefined ;
563
584
} else {
@@ -585,24 +606,31 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
585
606
}
586
607
}
587
608
588
- ngModel . $validators . date = validator ;
589
- ngModel . $parsers . unshift ( parseDate ) ;
590
-
591
- ngModel . $formatters . push ( function ( value ) {
592
- scope . date = value ;
593
- return ngModel . $isEmpty ( value ) ? value : dateFilter ( value , dateFormat ) ;
594
- } ) ;
609
+ if ( ! isHtml5DateInput ) {
610
+ // Internal API to maintain the correct ng-invalid-[key] class
611
+ ngModel . $$parserName = 'date' ;
612
+ ngModel . $validators . date = validator ;
613
+ ngModel . $parsers . unshift ( parseDate ) ;
614
+ ngModel . $formatters . push ( function ( value ) {
615
+ scope . date = value ;
616
+ return ngModel . $isEmpty ( value ) ? value : dateFilter ( value , dateFormat ) ;
617
+ } ) ;
618
+ }
619
+ else {
620
+ ngModel . $formatters . push ( function ( value ) {
621
+ scope . date = value ;
622
+ return value ;
623
+ } ) ;
624
+ }
595
625
596
626
// Inner change
597
627
scope . dateSelection = function ( dt ) {
598
628
if ( angular . isDefined ( dt ) ) {
599
629
scope . date = dt ;
600
630
}
601
- if ( dateFormat ) {
602
- var date = scope . date ? dateFilter ( scope . date , dateFormat ) : '' ;
603
- element . val ( date ) ;
604
- }
605
- ngModel . $setViewValue ( scope . date ) ;
631
+ var date = scope . date ? dateFilter ( scope . date , dateFormat ) : '' ;
632
+ element . val ( date ) ;
633
+ ngModel . $setViewValue ( date ) ;
606
634
607
635
if ( closeOnDateSelection ) {
608
636
scope . isOpen = false ;
@@ -612,7 +640,7 @@ function ($compile, $parse, $document, $position, dateFilter, dateParser, datepi
612
640
613
641
// Detect changes in the view from the text box
614
642
ngModel . $viewChangeListeners . push ( function ( ) {
615
- scope . date = ngModel . $viewValue ;
643
+ scope . date = dateParser . parse ( ngModel . $viewValue , dateFormat , scope . date ) || new Date ( ngModel . $viewValue ) ;
616
644
} ) ;
617
645
618
646
var documentClickBind = function ( event ) {
0 commit comments