Как изменить положение всплывающего окна элемента управления jQuery DatePicker

83

Любая идея, как заставить DatePicker появляться в конце связанного текстового поля, а не прямо под ним? То, что имеет тенденцию, состоит в том, что текстовое поле находится в нижней части страницы, а DatePicker сдвигается, чтобы учесть его и полностью покрывает текстовое поле. Если пользователь хочет ввести дату, а не выбрать ее, они не смогут. Я предпочел бы, чтобы он появился сразу после текстового поля, поэтому не имеет значения, как он настраивается по вертикали.

Любая идея, как управлять позиционированием? Я не видел никаких настроек для виджета, и мне не повезло с настройкой настроек CSS, но я мог легко что-то упустить.

  • 1
    +1 за то, что вы не просто «обратились» с жалобой на то, что ваше решение не является решением для D_N.
Теги:
jquery-ui-datepicker

20 ответов

26
Лучший ответ

Принятый ответ для этого вопроса на самом деле не для jQuery UI Datepicker. Чтобы изменить положение jQuery UI Datepicker, просто измените параметр .ui-datepicker в файле css. Размер Datepicker также можно изменить таким образом, просто отрегулируйте размер шрифта.

  • 0
    Не уверен, почему я изначально принял ответ Кева, потому что это не то, как я решил свою проблему. Я изменил .ui-datepicker, как описано выше. Должно быть, была долгая ночь. :)
  • 4
    Не могли бы вы сказать мне, скажите, какие изменения вы внесли?
Показать ещё 5 комментариев
114

Вот что я использую:

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

Вы также можете добавить немного больше в левое поле, чтобы оно не соответствовало поля ввода.

  • 2
    Хороший трюк. Проблема в том, что в тех случаях, когда указатель даты отображается за пределами экрана, _showDatepicker будет пытаться переместить его, поэтому верхний и левый будут отличаться, а marginTop, marginLeft может потребоваться настройка.
  • 1
    Я использовал аналогичный подход - я взял вашу идею использования beforeShow, но моя функция beforeShow использует эффект позиционирования JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField') (так как я использую опцию altField для отображения)
Показать ещё 5 комментариев
33

Я делаю это непосредственно в CSS:

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

Мои поля ввода даты имеют ширину 100 пикселей. Я также добавил z-индекс, поэтому календарь также появляется над всплывающими окнами AJAX.

Я не изменяю файл jquery-ui CSS; Я перегружаю класс в моем основном файле CSS, поэтому я могу изменить тему или обновить виджет, не переписывая свои конкретные моды.

  • 0
    Та же проблема, что и у другого css-трюка: работает, только если вы сейчас точно знаете, где должен быть указатель даты в CSS. Вы не можете использовать этот метод для динамического размещения средства выбора даты. Мне пришлось использовать хак, привязка к inst.input.focus ()
  • 0
    Я работал с помощью Bootstrap :), но я установил только свойство z-index.
Показать ещё 1 комментарий
26

Вот мой вариант выравнивания календаря Datepicker.

Я думаю, что это довольно хорошо, потому что вы можете управлять позиционированием через jQuery UI Position util.

Одно ограничение: требуется jquery.ui.position.js.

код:

$('input[name=date]').datepicker({
    beforeShow: function(input, inst) {
        // Handle calendar position before showing it.
        // It 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);
    }
})
  • 1
    у меня не работает
  • 0
    Спасибо @kottenator, это действительно полезно (особенно с position.js)!
Показать ещё 2 комментария
18

Вот еще один вариант, который хорошо работает для меня, отрегулируйте rect.top + 40, rect.left + 0 в соответствии с вашими потребностями:

$(".datepicker").datepicker({
    changeMonth: true,
    changeYear: true,
    dateFormat: 'mm/dd/yy',
    beforeShow: function (input, inst) {
        var rect = input.getBoundingClientRect();
        setTimeout(function () {
	        inst.dpDiv.css({ top: rect.top + 40, left: rect.left + 0 });
        }, 0);
    }
});
<link rel="stylesheet" href="/jquery-ui.css">
<script src="/jquery-1.10.2.js"></script>
<script src="/jquery-ui.js"></script>
<form>
<input class="datepicker" name="date1" type="text">
<input class="datepicker" name="date2" type="text">
</form>
  • 0
    Этот код решил мою проблему. Благодарю.
  • 0
    Вау, это работает. Использование "inst.dpDiv.css (" top "," 40px! Important ");" не работает!
Показать ещё 4 комментария
15

Это работает для меня:

 beforeShow: function(input, inst) {
     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);
6

Сначала я думаю, что в объекте datepicker должен быть метод afterShowing, где вы могли бы изменить позицию после того, как jquery выполнил все его voodoo в методе _showDatepicker. Кроме того, желателен параметр с именем preferedPosition, поэтому вы можете установить его, а jquery изменить его, если диалог отображается за пределами области просмотра.

Там есть "трюк", чтобы сделать это последнее. Если вы изучите метод _showDatepicker, вы увидите использование частной переменной $.datepikcer._pos. Эта переменная будет настроена, если никто ее не установил раньше. Если вы измените эту переменную перед отображением диалога, Jquery возьмет его и попытается выделить диалог в этой позиции, и если он отобразится вне экрана, он отрегулирует его, чтобы убедиться, что он виден. Звучит неплохо, а?

Проблема: _pos является закрытым, но если вы не возражаете против этого. Вы можете:

$('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
    }
});

Но будьте осторожны с обновлениями JQuery-ui, потому что изменение внутренней реализации _showDatepicker может нарушить ваш код.

  • 1
    Они должны были добавить это в jQuery UI как настраиваемый элемент.
3

Мне нужно было расположить datepicker в соответствии с родительским div, в котором находился мой входной контроль без полей. Для этого я использовал служебную программу "position", включенную в ядро ​​jQuery jquery. Я сделал это в событии beforeShow. Как отмечалось выше, вы не можете установить позицию непосредственно в beforeShow, так как код datepicker будет reset местоположением после завершения функции beforeShow. Чтобы обойти это, просто установите позицию, используя setInterval. Текущая script завершится, показывая datepicker, а затем код перестановки будет запускаться сразу же после просмотра даты. Хотя это никогда не должно происходить, если datepicker не отображается через 0,5 секунды, код имеет отказоустойчивость, чтобы отказаться и очистить интервал.

        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);
        }
  • 0
    Очень некрасивое решение. Самой большой проблемой был бы заметный «скачок» виджета DatePicker сразу после того, как он стал видимым, когда внезапно начинается ваше «перемещение». Избегать любой ценой.
2

связывать focusin после использования datepicker изменить css виджета datepicker пожелать помощи

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

i исправил его своим пользовательским кодом jquery.

  • предоставил поле ввода datepicker классу ".datepicker2"

  • найдите текущую позицию сверху и

  • позиционирует всплывающее окно, имя класса которого .ui-datepicker "

вот мой код.

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

здесь "40" - это мой ожидаемый пиксель, вы можете изменить его своим.

1

Я взял это из ((Как управлять позиционированием jQueryUI datepicker))

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

он работает!!!

  • 0
    Ответ правильный, хотя по существу уже отвечал раньше.
1

Они изменили имя класса на ui-datepicker-trigger

Итак, это работает в jquery 1.11.x

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

Я потратил нелепое время на то, чтобы понять эту проблему для нескольких страниц нового сайта, который я разрабатываю, и ничего не работало (включая любые из представленных выше решений, которые я реализовал. Я предполагаю jQuery только что изменил ситуацию, так как они предложили, чтобы решения не работали дольше. Я не знаю. Честно говоря, я не понимаю, почему в jQuery ui нет ничего простого, чтобы настроить это, поскольку это кажется довольно большой проблемой, когда календарь всегда появляется в некоторой позиции значительно далеко от страницы со входа, к которому он прикреплен.

Во всяком случае, я хотел, чтобы конечное решение было достаточно общим, чтобы я мог использовать его где угодно, и это сработает. Я, кажется, наконец пришел к выводу, что избегает некоторых более сложных и jQuery-специфичных для кода ответов выше:

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

По существу, я прикрепляю новый тег стиля к голове до каждого события showpicker "show" (удаляя предыдущий, если есть). Этот способ делать что-то происходит вокруг большого количества проблем, с которыми я столкнулся во время разработки.

Протестировано в Chrome, Firefox, Safari и IE > 8 (так как IE8 не работает с jsFiddle, и я теряю удовольствие от заботы

Я знаю, что это сочетание jQuery и javascript-контекстов, но на данный момент я просто не хочу прикладывать усилия для преобразования его в jQuery. Было бы просто, я знаю. Я так поступил с этой штукой прямо сейчас. Надеюсь, что кто-то может воспользоваться этим решением.

1

Исправить проблему с отображаемой позицией 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();
        }
    }
0

Здесь достаточно:

$(".date").datepicker({
    beforeShow: function(input, {
        inst.dpDiv.css({
            marginLeft: input.offsetWidth + "px"
        });
    }
});
0
.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}
  • 0
    почему проголосовал? это не решает проблему? codepen.io/coconewty/pen/rajbNj
  • 0
    votedown? Потому что вы только читали заголовок вопроса и не пытались разобраться в реальной проблеме. Просто предположим, что у вас есть два указателя даты, прикрепленные к полям ввода различной ширины. Как ваше решение гарантирует, что левый край каждого виджета DatePicker касается правого края поля ввода? С другой стороны, вы должны получить хотя бы одно очко за оригинальность ваших ответов.
0

Очень простая функция jquery.

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

Внутри Jquery.UI просто обновите функцию _checkOffset, так что viewHeight добавляется к offset.top, прежде чем возвращается смещение.

_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;
    },
  • 0
    Это решение по сути правильное: введите свою собственную функцию _checkOffset () через jQuery.extend () и верните произвольный объект, имеющий числовые свойства "top" и "left", то есть jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst) , offset, isFixed) {return {top: mytop , left: myleft };}}); где mytop и myleft по вашему вкусу, например, производные от inst .
0

Это помещает функциональность в метод с именем function, позволяя вашему коду инкапсулировать его или для того, чтобы метод стал расширением jquery. Просто используется для моего кода, отлично работает

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

Также стоит отметить, что если IE попадет в режим причуд, ваши компоненты jQuery UI и другие элементы будут неправильно установлены.

Чтобы убедиться, что вы не попали в режим quirks, убедитесь, что вы правильно настроили свой doctype на последний HTML5.

<!DOCTYPE html>

Использование перехода делает беспорядок вещей. Надеюсь, это спасет кого-то в будущем.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню