How to control positioning of jQueryUI datepicker

五迷三道 提交于 2019-11-28 03:34:30
JaredC

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.

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

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');
//... 
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!