[javascript] How to change the pop-up position of the jQuery DatePicker control

Any idea how to get the DatePicker to appear at the end of the associated text box instead of directly below it? What tends to happen is that the text box is towards the bottom of the page and the DatePicker shifts up to account for it and totally covers the text box. If the user wants to type the date instead of pick it, they can't. I'd rather have it appear just after the text box so it doesn't matter how it adjusts vertically.

Any idea how to control the positioning? I didn't see any settings for the widget, and I haven't had any luck tweaking the CSS settings, but I could easily be missing something.

This question is related to javascript jquery jquery-ui jquery-ui-datepicker

The answer is


bind focusin after using datepicker change css of datepicker`s widget wish help

$('input.date').datepicker();
$('input.date').focusin(function(){
    $('input.date').datepicker('widget').css({left:"-=127"});
});

Here is my variation of Datepicker calendar aligning.

I think that it's pretty nice, because you can control positioning via jQuery UI Position util.

One restriction: jquery.ui.position.js required.

Code:

$('input[name=date]').datepicker({
    beforeShow: function(input, inst) {
        // Handle calendar position before showing it.
        // It's not supported by Datepicker itself (for now) so we need to use its internal variables.
        var calendar = inst.dpDiv;

        // Dirty hack, but we can't do anything without it (for now, in jQuery UI 1.8.20)
        setTimeout(function() {
            calendar.position({
                my: 'right top',
                at: 'right bottom',
                collision: 'none',
                of: input
            });
        }, 1);
    }
})

This works for me:

beforeShow: function(input, inst) {
    var $this = $(this);
    var cal = inst.dpDiv;
    var top = $this.offset().top + $this.outerHeight();
    var left = $this.offset().left;

    setTimeout(function() {
        cal.css({
            'top': top,
            'left': left
        });
    }, 10);
}

fix show position problem daterangepicker.jQuery.js

//Original Code
//show, hide, or toggle rangepicker
    function showRP() {
        if (rp.data('state') == 'closed') {
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        }
    }


//Fixed
//show, hide, or toggle rangepicker
    function showRP() {
        rp.parent().css('left', rangeInput.offset().left);
        rp.parent().css('top', rangeInput.offset().top + rangeInput.outerHeight());
        if (rp.data('state') == 'closed') {
            rp.data('state', 'open');
            rp.fadeIn(300);
            options.onOpen();
        }
    }

First I think there should be a afterShowing method in the datepicker object, where you could change the position after jquery has done all its voodoo in the _showDatepicker method. Additionally, a parameter called preferedPosition would be also desirable, so you could set it and jquery modify it in case the dialog is rendered outside the viewport.

There's a "trick" to do this last thing. If you study the _showDatepicker method, you will see the use of a private variable $.datepikcer._pos. That variable will be setup if nobody has set it up before. If you modify that variable before showing the dialog, Jquery will take it and will try to allocate the dialog in that position, and if it renders out of the screen, it will adjust it to make sure it is visible. Sounds good, eh?

Problem is; _pos is private, but if you don't mind that. You can:

$('input.date').datepicker({
    beforeShow: function(input, inst)
    {
        $.datepicker._pos = $.datepicker._findPos(input); //this is the default position
        $.datepicker._pos[0] = whatever; //left
        $.datepicker._pos[1] = whatever; //top
    }
});

But be careful of Jquery-ui updates, because a change in the internal implementation of the _showDatepicker might break your code.


Here is another variation that works well for me, adjust the rect.top + 40, rect.left + 0 to suit your needs:

_x000D_
_x000D_
$(".datepicker").datepicker({_x000D_
    changeMonth: true,_x000D_
    changeYear: true,_x000D_
    dateFormat: 'mm/dd/yy',_x000D_
    beforeShow: function (input, inst) {_x000D_
        var rect = input.getBoundingClientRect();_x000D_
        setTimeout(function () {_x000D_
         inst.dpDiv.css({ top: rect.top + 40, left: rect.left + 0 });_x000D_
        }, 0);_x000D_
    }_x000D_
});
_x000D_
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">_x000D_
<script src="//code.jquery.com/jquery-1.10.2.js"></script>_x000D_
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>_x000D_
<form>_x000D_
<input class="datepicker" name="date1" type="text">_x000D_
<input class="datepicker" name="date2" type="text">_x000D_
</form>
_x000D_
_x000D_
_x000D_


A very simple jquery function.

$(".datepicker").focus(function(event){
                var dim = $(this).offset();
                $("#ui-datepicker-div").offset({
                    top     :   dim.top - 180,
                    left    :   dim.left + 150
                });
            });

.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}

$('.PDatePicker').MdPersianDateTimePicker({
                Placement: 'top',          
            });

This puts the functionality into a method named function, allowing for your code to encapsulate it or for the method to be made a jquery extension. Just used on my code, works perfectly

var nOffsetTop  = /* whatever value, set from wherever */;
var nOffsetLeft = /* whatever value, set from wherever */;

$(input).datepicker
(
   beforeShow : function(oInput, oInst) 
   { 
      AlterPostion(oInput, oInst, nOffsetTop, nOffsetLeft); 
   }
);

/* can be converted to extension, or whatever*/
var AlterPosition = function(oInput, oItst, nOffsetTop, nOffsetLeft)
{
   var divContainer = oInst.dpDiv;
   var oElem        = $(this);
       oInput       = $(oInput);

   setTimeout(function() 
   { 
      divContainer.css
      ({ 
         top  : (nOffsetTop >= 0 ? "+=" + nOffsetTop : "-=" + (nOffsetTop * -1)), 
         left : (nOffsetTop >= 0 ? "+=" + nOffsetLeft : "-=" + (nOffsetLeft * -1))
      }); 
   }, 10);
}

i fixed it with my custom jquery code.

  1. gave my datepicker input field a class ".datepicker2"

  2. find its current position from top and

  3. positioned the popup box, which class name is ".ui-datepicker"

here is my code.

$('.datepicker2').click(function(){
    var popup =$(this).offset();
    var popupTop = popup.top - 40;
    $('.ui-datepicker').css({
      'top' : popupTop
     });
});

here "40" is my expected pixel, you may change with yours.


I spent a ridiculous amount of time trying to figure this problem out for several pages of a new site I'm developing and nothing seemed to work (including any of the various solutions presented above that I implemented. I'm guessing jQuery has just changed things up enough since they were suggested that the solutions dont' work any longer. I don't know. Honestly, I don't understand why there isn't something simple implemented into the jQuery ui to configure this, as it seems to be a fairly large issue with the calendar always popping up at some position considerably far down the page from the input to which it is attached.

Anyhow, I wanted an end solution that was generic enough that I could use it anywhere and it would work. I seem to have finally come to a conclusion that avoids some of the more complicated and jQuery-code-specific answers above:

jsFiddle: http://jsfiddle.net/mu27tLen/

HTML:

<input type="text" class="datePicker" />

JS:

positionDatePicker= function(cssToAdd) {
    /* Remove previous positioner */
    var oldScript= document.getElementById('datePickerPosition');
    if(oldScript) oldScript.parentNode.removeChild(oldScript);
    /* Create new positioner */
    var newStyle= document.createElement("style");
    newStyle.type= 'text/css';
    newStyle.setAttribute('id', 'datePickerPostion');
    if(newStyle.styleSheet) newStyle.styleSheet.cssText= cssToAdd;
    else newStyle.appendChild(document.createTextNode(cssToAdd));
    document.getElementsByTagName("head")[0].appendChild(newStyle);
}
jQuery(document).ready(function() {
    /* Initialize date picker elements */
    var dateInputs= jQuery('input.datePicker');
    dateInputs.datepicker();
    dateInputs.datepicker('option', {
        'dateFormat' : 'mm/dd/yy',
        'beforeShow' : function(input, inst) {
            var bodyRect= document.body.getBoundingClientRect();
            var rect= input.getBoundingClientRect();
            positionDatePicker('.page #ui-datepicker-div{z-index:100 !important;top:' + (rect.top - bodyRect.top + input.offsetHeight + 2) + 'px !important;}');
        }
    }).datepicker('setDate', new Date());
});

Essentially I attach a new style tag to the head prior to every datepicker "show" event (deleting the previous one, if present). This method of doing things gets around a large majority of the issues that I ran into during development.

Tested on Chrome, Firefox, Safari, and IE>8 (as IE8 doesn't work well with jsFiddle and I'm losing my gusto for caring about

I know that this is a mix of jQuery and javascript contexts, but at this point I just don't want to put the effort into converting it to jQuery. Would be simple, I know. I'm so done with this thing right now. Hope someone else can benefit from this solution.


Or you can use the focus event on your dateSelect object and position api together. You can swap top and bottom and left for right or center (or really anything you want from the position api). This way you don't need an interval or any insanely complex solution and you can configure the layout to suit your needs depending on where the input is.

dateSelect.focus(function () {
    $("#ui-datepicker-div").position({
        my: "left top",
        at: "left bottom",
        of: $(this)
    });
});

Here's what I'm using:

$('input.date').datepicker({
    beforeShow: function(input, inst) {
        inst.dpDiv.css({
            marginTop: -input.offsetHeight + 'px', 
            marginLeft: input.offsetWidth + 'px'
        });
    }
});

You may also want to add a bit more to the left margin so it's not right up against the input field.


I took it from ((How to control positioning of jQueryUI datepicker))

$.extend($.datepicker, { 
    _checkOffset: function(inst, offset, isFixed) { 
        return offset 
    } 
});

it works !!!


I needed to position the datepicker according to a parent div within which my borderless input control resided. To do it, I used the "position" utility included in jquery UI core. I did this in the beforeShow event. As others commented above, you can't set the position directly in beforeShow, as the datepicker code will reset the location after finishing the beforeShow function. To get around that, simply set the position using setInterval. The current script will complete, showing the datepicker, and then the repositioning code will run immediately after the datepicker is visible. Though it should never happen, if the datepicker isn't visible after .5 seconds, the code has a fail-safe to give up and clear the interval.

        beforeShow: function(a, b) {
            var cnt = 0;
            var interval = setInterval(function() {
                cnt++;
                if (b.dpDiv.is(":visible")) {
                    var parent = b.input.closest("div");
                    b.dpDiv.position({ my: "left top", at: "left bottom", of: parent });
                    clearInterval(interval);
                } else if (cnt > 50) {
                    clearInterval(interval);
                }
            }, 10);
        }

Within Jquery.UI, just update the _checkOffset function, so that viewHeight is added to offset.top, before offset is returned.

_checkOffset: function(inst, offset, isFixed) {
    var dpWidth = inst.dpDiv.outerWidth(),
    dpHeight = inst.dpDiv.outerHeight(),
    inputWidth = inst.input ? inst.input.outerWidth() : 0,
    inputHeight = inst.input ? inst.input.outerHeight() : 0,
    viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
            viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : ($(document).scrollTop()||document.body.scrollTop));
        offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
        offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
        offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? ($(document).scrollTop()||document.body.scrollTop) : 0;

        // now check if datepicker is showing outside window viewport - move to a better place if so.
        offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
            Math.abs(offset.left + dpWidth - viewWidth) : 0);
        offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
            Math.abs(dpHeight + inputHeight) : 0);
**offset.top = offset.top + viewHeight;**
        return offset;
    },

It's also worth noting that if IE falls into quirks mode, your jQuery UI components, and other elements, will be positioned incorrectly.

To make sure you don't fall into quirks mode, make sure you set your doctype correctly to the latest HTML5.

<!DOCTYPE html>

Using transitional makes a mess of things. Hopefully this will save someone some time in the future.


They changed the classname to ui-datepicker-trigger

So this works in jquery 1.11.x

.ui-datepicker-trigger { 
margin-top:7px;
  margin-left: -30px;
  margin-bottom:0px;
  position:absolute;
  z-index:1000;
}

I do it directly in the CSS:

.ui-datepicker { 
  margin-left: 100px;
  z-index: 1000;
}

My date input fields are all 100px wide. I also added the z-index so the calendar also appears above AJAX popups.

I don't modify the jquery-ui CSS file; I overload the class in my main CSS file, so I can change the theme or update the widget without having to re-enter my specific mods.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to jquery-ui

How to auto adjust the div size for all mobile / tablet display formats? jQuery not working with IE 11 JavaScript Uncaught ReferenceError: jQuery is not defined; Uncaught ReferenceError: $ is not defined Best Practice to Organize Javascript Library & CSS Folder Structure Change table header color using bootstrap How to get HTML 5 input type="date" working in Firefox and/or IE 10 Form Submit jQuery does not work Disable future dates after today in Jquery Ui Datepicker How to Set Active Tab in jQuery Ui How to use source: function()... and AJAX in JQuery UI autocomplete

Examples related to jquery-ui-datepicker

How to format date with hours, minutes and seconds when using jQuery UI Datepicker? Jquery UI datepicker. Disable array of Dates How to set minDate to current date in jQuery UI Datepicker? Jquery DatePicker Set default date jQuery UI: Datepicker set year range dropdown to 100 years How to add/subtract dates with JavaScript? setting min date in jquery datepicker How do I clear/reset the selected dates on the jQuery UI Datepicker calendar? jQuery Date Picker - disable past dates Getting value from JQUERY datepicker