Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit f9903ba

Browse files
RobJacobswesleycho
authored andcommitted
feat(datepicker): implement auto position
Added popup-placement attribute that implements the auto position feature that exists in the tooltip directive. Accepts the same placement options as the tooltip. Closes #5444
1 parent b835332 commit f9903ba

File tree

3 files changed

+67
-9
lines changed

3 files changed

+67
-9
lines changed

src/datepicker/datepicker.css

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
.uib-datepicker-popup.dropdown-menu {
1010
display: block;
11+
float: none;
12+
visibility: hidden;
13+
margin: 0;
14+
top: -9999px;
15+
left: -9999px;
1116
}
1217

1318
.uib-button-bar {

src/datepicker/datepicker.js

+42-7
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
332332
} else {
333333
self.activeDate = date;
334334
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) - 1];
335+
$scope.$emit('uib:datepicker.mode');
335336
}
336337
};
337338

@@ -351,6 +352,7 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
351352
}
352353

353354
$scope.datepickerMode = self.modes[self.modes.indexOf($scope.datepickerMode) + direction];
355+
$scope.$emit('uib:datepicker.mode');
354356
};
355357

356358
// Key event mapper
@@ -717,15 +719,16 @@ angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootst
717719
'month': 'yyyy-MM'
718720
},
719721
onOpenFocus: true,
720-
showButtonBar: true
722+
showButtonBar: true,
723+
placement: 'auto bottom-left'
721724
})
722725

723-
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
724-
function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
726+
.controller('UibDatepickerPopupController', ['$scope', '$element', '$attrs', '$compile', '$log', '$parse', '$window', '$document', '$rootScope', '$uibPosition', 'dateFilter', 'uibDateParser', 'uibDatepickerPopupConfig', '$timeout', 'uibDatepickerConfig', 'uibDatepickerPopupAttributeWarning',
727+
function($scope, $element, $attrs, $compile, $log, $parse, $window, $document, $rootScope, $position, dateFilter, dateParser, datepickerPopupConfig, $timeout, datepickerConfig, datepickerPopupAttributeWarning) {
725728
var cache = {},
726729
isHtml5DateInput = false;
727730
var dateFormat, closeOnDateSelection, appendToBody, onOpenFocus,
728-
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl,
731+
datepickerPopupTemplateUrl, datepickerTemplateUrl, popupEl, datepickerEl, scrollParentEl,
729732
ngModel, ngModelOptions, $popup, altInputFormats, watchListeners = [];
730733

731734
$scope.watchData = {};
@@ -965,6 +968,10 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
965968
$popup.remove();
966969
$element.off('keydown', inputKeydownBind);
967970
$document.off('click', documentClickBind);
971+
if (scrollParentEl) {
972+
scrollParentEl.off('scroll', positionPopup);
973+
}
974+
angular.element($window).off('resize', positionPopup);
968975

969976
//Clear all watch listeners on destroy
970977
while (watchListeners.length) {
@@ -1045,20 +1052,35 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
10451052
$scope.$watch('isOpen', function(value) {
10461053
if (value) {
10471054
if (!$scope.disabled) {
1048-
$scope.position = appendToBody ? $position.offset($element) : $position.position($element);
1049-
$scope.position.top = $scope.position.top + $element.prop('offsetHeight');
1050-
10511055
$timeout(function() {
1056+
positionPopup();
1057+
10521058
if (onOpenFocus) {
10531059
$scope.$broadcast('uib:datepicker.focus');
10541060
}
10551061
$document.on('click', documentClickBind);
1062+
1063+
var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
1064+
if (appendToBody || $position.parsePlacement(placement)[2]) {
1065+
scrollParentEl = scrollParentEl || angular.element($position.scrollParent($element));
1066+
if (scrollParentEl) {
1067+
scrollParentEl.on('scroll', positionPopup);
1068+
}
1069+
} else {
1070+
scrollParentEl = null;
1071+
}
1072+
1073+
angular.element($window).on('resize', positionPopup);
10561074
}, 0, false);
10571075
} else {
10581076
$scope.isOpen = false;
10591077
}
10601078
} else {
10611079
$document.off('click', documentClickBind);
1080+
if (scrollParentEl) {
1081+
scrollParentEl.off('scroll', positionPopup);
1082+
}
1083+
angular.element($window).off('resize', positionPopup);
10621084
}
10631085
});
10641086

@@ -1162,6 +1184,19 @@ function($scope, $element, $attrs, $compile, $log, $parse, $document, $rootScope
11621184
});
11631185
}
11641186
}
1187+
1188+
function positionPopup() {
1189+
if ($scope.isOpen) {
1190+
var dpElement = $popup[0].querySelector('.uib-datepicker-popup');
1191+
var placement = $attrs.popupPlacement ? $attrs.popupPlacement : datepickerPopupConfig.placement;
1192+
var position = $position.positionElements($element, dpElement, placement, appendToBody);
1193+
angular.element(dpElement).css({top: position.top + 'px', left: position.left + 'px', visibility: 'visible'});
1194+
}
1195+
}
1196+
1197+
$scope.$on('uib:datepicker.mode', function() {
1198+
$timeout(positionPopup, 0, false);
1199+
});
11651200
}])
11661201

11671202
.directive('uibDatepickerPopup', function() {

src/datepicker/docs/readme.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ The datepicker has 3 modes:
7878
* `format-month-title`
7979
<small class="badge">C</small>
8080
_(Default: `yyyy`)_ -
81-
Format of title when selecting month.
81+
Format of title when selecting month.
8282

8383
* `init-date`
8484
<small class="badge">$</small>
@@ -210,7 +210,7 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
210210
* `datepicker-template-url`
211211
<small class="badge">C</small>
212212
_(Default: `uib/template/datepicker/datepicker.html`)_ -
213-
Add the ability to override the template used on the component (inner uib-datepicker).
213+
Add the ability to override the template used on the component (inner uib-datepicker).
214214

215215
* `is-open`
216216
<small class="badge">$</small>
@@ -235,6 +235,24 @@ The popup is a wrapper that you can use in an input to toggle a datepicker. To c
235235
_(Default: `text`, Config: `html5Types`)_ -
236236
You can override the input type to be _(date|datetime-local|month)_. That will change the date format of the popup.
237237

238+
* `popup-placement`
239+
<small class="badge">C</small>
240+
_(Default: `auto bottom-left`, Config: 'placement')_ -
241+
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:
242+
243+
* `top` - popup on top, horizontally centered on input element.
244+
* `top-left` - popup on top, left edge aligned with input element left edge.
245+
* `top-right` - popup on top, right edge aligned with input element right edge.
246+
* `bottom` - popup on bottom, horizontally centered on input element.
247+
* `bottom-left` - popup on bottom, left edge aligned with input element left edge.
248+
* `bottom-right` - popup on bottom, right edge aligned with input element right edge.
249+
* `left` - popup on left, vertically centered on input element.
250+
* `left-top` - popup on left, top edge aligned with input element top edge.
251+
* `left-bottom` - popup on left, bottom edge aligned with input element bottom edge.
252+
* `right` - popup on right, vertically centered on input element.
253+
* `right-top` - popup on right, top edge aligned with input element top edge.
254+
* `right-bottom` - popup on right, bottom edge aligned with input element bottom edge.
255+
238256
* `uib-datepicker-popup`
239257
<small class="badge">C</small>
240258
_(Default: `yyyy-MM-dd`, Config: `datepickerConfig`)_ -

0 commit comments

Comments
 (0)