How to control positioning of jQueryUI datepicker

63,668

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

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

Solution 5

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,
        };
    }
});
Share:
63,668
Purrell
Author by

Purrell

Updated on August 17, 2020

Comments

  • Purrell
    Purrell almost 4 years

    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:

  • Purrell
    Purrell about 14 years
    No prob - I'm happy somebody else got something out of this, I remember spending an hour or two figuring this out.
  • bbeckford
    bbeckford over 13 years
    Nice one, really helped me! For anyone who needs it you can then change the margins of the datepicker like this: .ui-datepicker { margin-left: -361px; }
  • Jilco Tigchelaar
    Jilco Tigchelaar over 11 years
    eeehh, maybe a stupid question, but how to use this? In beforeshow?
  • Felix Wessendorf
    Felix Wessendorf over 11 years
    Works like a charm. @JilcoTigchelaar I'm just making the function returning a fixed offset. $.extend($.datepicker,{_checkOffset:function(inst,offset,isF‌​ixed){offset.top = 80; offset.left=180; return offset;}});
  • mutanic
    mutanic over 11 years
    Sorry for ask this but how do I use it? To be specific, where should I put that line?
  • LGAP
    LGAP over 11 years
    when you already see an answer accepted, whats the point in answering again. Anyway, Welcome to SO! :)
  • Katai
    Katai over 11 years
    @hcharge actually, they dont, if you use !important inside the CSS style. Only inline styles having !important themselves can then overwrite the !important coming from CSS - jsfiddle.net/NTCP7
  • Neil Laslett
    Neil Laslett almost 11 years
    While !important is a bit of a CSS hack of last resort, this solution works well and is the easiest to implement.
  • Adi
    Adi about 10 years
    @mutanic - $(document).ready(function () {put the line here});
  • wh81752
    wh81752 almost 9 years
    This answer is wrong cause the thread started asked quite specifically for a static render location. Your answer simply shifts the location 50px to the left.
  • wh81752
    wh81752 almost 9 years
    This solution is nothing more than a hack. Although it works in general, you may notice a kind of "jump" on the datepicker widget, especially if the position generated by datepicker is far away from your "hacked" position. This is of course only secondary, cause your solution may not work at all on "slow" computers.
  • wh81752
    wh81752 almost 9 years
    Your problem misses a correlation with the stated problem of this thread. Second, why applying css properties via JS and not via CSS stylesheets?
  • wh81752
    wh81752 almost 9 years
    This answer is correct to the very specific problem of positioning the datepicker calendar widget at an absolute position. The answer is not correct in regard to the more general title "How to control positioning of jQueryUI datepicker?"
  • CodeLama
    CodeLama about 8 years
    Showing way how to do it without a 'hack' is always a goot thing. Accepted solution (overriding internal 'private' logic of datepicker) may broke that fix with each new version of jquery.ui. Looking at accepted answer it actually seems to me like that is the case...
  • mpen
    mpen about 8 years
    Your coffee is riddled with syntax errors. Would you mind fixing them? Or better yet, transpiling it to JS for us? Edit: Nvm, SO just screwed up the spacing. This is why I hate whitespace-dependent languages. I'm amending your answer with the JS, hope that's OK.
  • David Hunt
    David Hunt over 6 years
    I found this to be the most useful with the latest jQuery UI versions
  • JonSnow
    JonSnow about 5 years
    Interesting. But how can I use this on specific datepickers only? It seems not to work with standard DPs, only with the ones included in a dialog in my case.
  • mpen
    mpen about 5 years
    @SchweizerSchoggi Not sure. If you can obtain an instance of the datepicker object, you might be able to overwrite _checkOffset for that instance only. Oh, but this code does check if the datepicker is "fixed" or not, maybe you could just tweak that logic to suit your needs.
  • celerno
    celerno almost 3 years
    I have used your solution but added + inst.input[0].clientHeight to the rect.top return value!. thanks