diff --git a/src/datepicker/datepicker.css b/src/datepicker/datepicker.css
index a9af3ab849..64c7cc5c62 100644
--- a/src/datepicker/datepicker.css
+++ b/src/datepicker/datepicker.css
@@ -8,6 +8,11 @@
.uib-datepicker-popup.dropdown-menu {
display: block;
+ float: none;
+ visibility: hidden;
+ margin: 0;
+ top: -9999px;
+ left: -9999px;
}
.uib-button-bar {
diff --git a/src/datepicker/datepicker.js b/src/datepicker/datepicker.js
index eb514561a3..f810996bb8 100644
--- a/src/datepicker/datepicker.js
+++ b/src/datepicker/datepicker.js
@@ -332,6 +332,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
} else {
self.activeDate = date;
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
+ $scope.$emit('uib:datepicker.mode');
}
};
@@ -351,6 +352,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
}
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
+ $scope.$emit('uib:datepicker.mode');
};
// Key event mapper
@@ -717,15 +719,16 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
'month': 'yyyy-MM'
},
onOpenFocus: true,
- showButtonBar: true
+ showButtonBar: true,
+ placement: 'auto bottom-left'
})
-.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
-function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
+.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$window', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
+function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
var cache = {},
isHtml5DateInput = false;
var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
- datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
+ datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl, scrollParentEl,
ngModel, ngModelOptions, $popup, altInputFormats, watchListeners = [];
$scope.watchData = {};
@@ -965,6 +968,10 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
$popup.remove();
$element.off('keydown', inputKeydownBind);
$document.off('click', documentClickBind);
+ if (scrollParentEl) {
+ scrollParentEl.off('scroll', positionPopup);
+ }
+ angular.element($window).off('resize', positionPopup);
//Clear all watch listeners on destroy
while (watchListeners.length) {
@@ -1045,20 +1052,35 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
$scope.$watch('isOpen', function(value) {
if (value) {
if (!$scope.disabled) {
- $scope.position = appendToBody ? $position.offset($element) : $position.position($element);
- $scope.position.top = $scope.position.top + $element.prop('offsetHeight');
-
$timeout(function() {
+ positionPopup();
+
if (onOpenFocus) {
$scope.$broadcast('uib:datepicker.focus');
}
$document.on('click', documentClickBind);
+
+ var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
+ if (appendToBody || $position.parsePlacement(placement)[2]) {
+ scrollParentEl = scrollParentEl || angular.element($position.scrollParent($element));
+ if (scrollParentEl) {
+ scrollParentEl.on('scroll', positionPopup);
+ }
+ } else {
+ scrollParentEl = null;
+ }
+
+ angular.element($window).on('resize', positionPopup);
}, 0, false);
} else {
$scope.isOpen = false;
}
} else {
$document.off('click', documentClickBind);
+ if (scrollParentEl) {
+ scrollParentEl.off('scroll', positionPopup);
+ }
+ angular.element($window).off('resize', positionPopup);
}
});
@@ -1162,6 +1184,19 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
});
}
}
+
+ function positionPopup() {
+ if ($scope.isOpen) {
+ var dpElement = $popup[0].querySelector('.uib-datepicker-popup');
+ var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
+ var position = $position.positionElements($element, dpElement, placement, appendToBody);
+ angular.element(dpElement).css({top: position.top + 'px', left: position.left + 'px', visibility: 'visible'});
+ }
+ }
+
+ $scope.$on('uib:datepicker.mode', function() {
+ $timeout(positionPopup, 0, false);
+ });
}])
.directive('uibDatepickerPopup', function() {
diff --git a/src/datepicker/docs/readme.md b/src/datepicker/docs/readme.md
index f97a83099e..3c15f891f1 100644
--- a/src/datepicker/docs/readme.md
+++ b/src/datepicker/docs/readme.md
@@ -78,7 +78,7 @@ The datepicker has 3 modes:
* `format-month-title`
C
_(Default: `yyyy`)_ -
- Format of title when selecting month.
+ Format of title when selecting month.
* `init-date`
$
@@ -210,7 +210,7 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
* `datepicker-template-url`
C
_(Default: `uib/template/datepicker/datepicker.html`)_ -
- Add the ability to override the template used on the component (inner uib-datepicker).
+ Add the ability to override the template used on the component (inner uib-datepicker).
* `is-open`
$
@@ -235,6 +235,24 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
_(Default: `text`, Config: `html5Types`)_ -
You can override the input type to be _(date|datetime-local|month)_. That will change the date format of the popup.
+* `popup-placement`
+ C
+ _(Default: `auto bottom-left`, Config: 'placement')_ -
+ Passing in 'auto' separated by a space before the placement will enable auto positioning, e.g: "auto bottom-left". The popup will attempt to position where it fits in the closest scrollable ancestor. Accepts:
+
+ * `top` - popup on top, horizontally centered on input element.
+ * `top-left` - popup on top, left edge aligned with input element left edge.
+ * `top-right` - popup on top, right edge aligned with input element right edge.
+ * `bottom` - popup on bottom, horizontally centered on input element.
+ * `bottom-left` - popup on bottom, left edge aligned with input element left edge.
+ * `bottom-right` - popup on bottom, right edge aligned with input element right edge.
+ * `left` - popup on left, vertically centered on input element.
+ * `left-top` - popup on left, top edge aligned with input element top edge.
+ * `left-bottom` - popup on left, bottom edge aligned with input element bottom edge.
+ * `right` - popup on right, vertically centered on input element.
+ * `right-top` - popup on right, top edge aligned with input element top edge.
+ * `right-bottom` - popup on right, bottom edge aligned with input element bottom edge.
+
* `uib-datepicker-popup`
C
_(Default: `yyyy-MM-dd`, Config: `datepickerConfig`)_ -