Question

The datepicker in jQueryUI renders with a dynamic position. It renders according to its css if there's enough room for it, but if there isn't enough window space it tries to render on screen. I need it to stay put and render in the same place every time, independent of the screen position or other circumstances. How can this be done with the jQueryUI datepicker? Other implementations of jQuery datepicker seem to have ways of doing this, but I don't see a way of doing it for the UI version.

The answer doesn't seem to be just modifying the css:

.ui-datepicker { width: 17em; padding: .2em .2em 0; (trying top/margin-top/position:relative, etc. here...)}

...since when the datepicker is created it dynamically creates top and left in element style. Haven't found a way around this yet. One approach I saw is to give something like this in the beforeShow option:

beforeShow: function(input,inst){
                                inst.dpDiv.css({ 
                                   'top': input.offsetHeight+ 'px', 
                                   'left':(input.offsetWidth - input.width)+ 'px'
                                               });
                                }

This has some effect but the top and left properties are still being dynamically set after this is run when the datepicker renders. It's still trying to render on screen. How do I get it to always render in the same spot? My next step is probably to go into the datepicker guts and start pulling things out. Any ideas?

Note that the answer (for the UI version) is not in:

Was it helpful?

Solution

Posting this in hopes that it will help others. At least as of v1.8.1 of datepicker, using 'window.DP_jQuery.datepicker' no longer works, because the pointer(right term?) now is named with a timestamp of its creation - so for example it would now be 'window.DP_jQuery_1273700460448'. So now, rather than using the pointer to the datepicker object, refer to it directly like this:

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

Many thanks for the answer below for getting me what I needed.

OTHER TIPS

Edit: JaredC gave an updated answer for later versions of jQuery above. Switching accepted answer to that.

Alright, this is a matter of monkeypatching the feature it has of attempting to always render in the viewport since there's no option provided to enable/disable the feature. Luckily it's uncoupled and isolated in one function so we can just go in and override it. The following code completely disables that feature only:

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

_checkOffset is called when it's opening and it does calculations on the offset and returns a new offset if it would otherwise be outside of the view port. This replaces the function body to just pass the original offset right through. Then you can use the beforeShow setting hack and/or the .ui-datepicker css class to put it wherever you want.

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"});
});

with jQuery:

beforeShow : function(input,inst){
    var offset = $(input).offset();
    var height = $(input).height();
    window.setTimeout(function () {
        $(inst.dpDiv).css({ top: (offset.top + height) + 'px', left:offset.left + 'px' })
    }, 1);
}

The problem I was having is that the datepicker is positioned incorrectly inside fixed elements, such as fancy/lightboxes. For some reason, the datepicker switches into "fixed" positioning mode when this happens, and then the offset calculation becomes incorrect, when absolute positioning would have worked just fine.

However, we can get the correct fixed position with this hack:

const checkOffset = $.datepicker._checkOffset;

$.extend($.datepicker, {
    _checkOffset: function(inst, offset, isFixed) {
        if(!isFixed) {
            return checkOffset.apply(this, arguments);
        }

        let isRTL = this._get(inst, "isRTL");
        let obj = inst.input[0];

        while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
            obj = obj[isRTL ? "previousSibling" : "nextSibling"];
        }

        let rect = obj.getBoundingClientRect();

        return {
            top: rect.top,
            left: rect.left,
        };
    }
});

In your css file, for example:

#ui-datepicker-div {
  position: absolute !important;
  top: auto !important;
  left: auto !important;
}

Your important settings, whatever they are, will override the inline defaults.

earlier i tried giving top, left in beforeShow event of datepicker.js, that's get override by _showDatePicker method of jquery-ui-custom.js . But after timeout the window its working fine. Below is the code

beforeShow : function(input,inst) {
  var offset = js.select("#" + dpId).offset();
                        var height = js.select("#" + dpId).height();
                        var width = js.select("#" + dpId).width();
                        window.setTimeout(function () {
                              js.select(inst.dpDiv).css({ top: (offset.top + height - 185) + 'px', left: (offset.left + width + 50) + 'px' })
                        }, 1);
}

This is quite an old question however I recently ran into an issue similar to this with the jQuery UI Datepicker. We were already using the solution posted by @JaredC above (specifically this code snippet: $.extend($.datepicker,{_checkOffset:function(inst,offset,isFixed){return offset}});) however it would not work for a modal that had an input in which we needed to render a dropdown.

This issue would occur because when scrolling down the page the offset of the input in the modal changes relative to the top of the scrolled page. The resulting behavior would mean that the datepicker would render in a different vertical position depending on how far you scrolled down the page (note: while visible and scrolling the datepicker was already fixed). The solution to this issue ("datepicker input nested within a modal") is to instead calculate the vertical positioning of the input relative to the view screen and then add the height of the input (allowing the "top" css property of the datepicker to be right below that of the input).

The following snippet is in coffeescript. Instead of returning the regular offset as per @JaredC's solution we instead obtain the elementId of the input from the 'inst' object and then access the object via jquery in order to use it to calculate the input's distance from the top of the screen relative to the viewport.

# CoffeeScript
$.extend( $.datepicker, { _checkOffset: (inst,offset,isFixed) ->
        offset.top = $("##{inst.id}").offset().top - $(window).scrollTop() + $("##{inst.id}")[0].getBoundingClientRect().height
        offset
    }
)

// JavaScript
$.extend($.datepicker, {
    _checkOffset: function(inst, offset, isFixed) {
        offset.top = $("#" + inst.id).offset().top - $(window).scrollTop() + $("#" + inst.id)[0].getBoundingClientRect().height;
        return offset;
    }
});

The accepted answer works very well overall.

However, using jQuery UI v1.11.4, I had an issue where the datepicker would position itself away from the input in a modal window (fixed positioning) when the browser window has been scrolled down. I was able to fix this problem editing the accepted answer as follows:

const checkOffset = $.datepicker._checkOffset;

$.extend($.datepicker, {
  _checkOffset: function(inst, offset, isFixed) {
    if(isFixed) {
      return checkOffset.apply(this, arguments);
    } else {
      return offset;
    }
  }
});
$("first-selector").datepicker().bind('click',function () {
      $("#ui-datepicker-div").appendTo("other-selector");
});

<style>
#ui-datepicker-div {
        position: absolute !important;
        top: auto !important;
        left: auto !important;
        z-index: 99999999 !important;
}
</style>

This is how it worked out for me:

$( "input[name='birthdate']" ).datepicker({
    beforeShow : function(input,inst){
    window.setTimeout(function () {
        $("#ui-datepicker-div").position({ my: "left top", at: "left bottom", of: input });
    }, 1);
    }
});

To get it positioned when the screen gets resized:

$(window).resize(function(){ $("#ui-datepicker-div").position({ my: "left top", at: "left bottom", of: "input[name='birthdate']" }); });

here is a more simple solution

var $picker = $( ".myspanclass" ).datepicker(); // span has display: inline-block
$picker.find('.ui-datepicker').css('margin-left', '-50px');

By default the calendar of the date picker was display to the upper-right of my input box, so the top of it was hidden by my menu bar. Here's how I positioned the widget (jquery-ui version 1.11.4) very simply (note that 'ui-datepicker' is the class name given by jquery-ui):

$(document).ready(function() {
$(".ui-datepicker").css('margin-left', '-50px', 'margin-top', '-50px');
//... 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top