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


109

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

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


1
+1 за то, что не просто "обратился" к жалобе, что ваше решение не является решением для D_N.
Леонидас

Ответы:


20

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


4
Не могли бы вы сказать мне, какие изменения вы внесли?
eddy

1
@gfrizzle - да, этот мой ответ был совершенно неправильным. Наконец добрались до мусора. Понятия не имею, о чем я тогда думал: /
Кев

64
Я понятия не имею, почему это общепринятый ответ, поскольку он практически бесполезен.
Software Engineer

10
Данный ответ является совершенно бесполезным , так как DatePicker будет динамически CSS модифицирует .ui-Datepicker перед выскакивает виджет.
whaefelinger

4
Этот ответ не содержит подробностей и не должен быть принятым ответом.
chapeljuice

120

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

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

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


2
Хорошая уловка. Проблема в том, что в тех случаях, когда datepicker отображается за пределами экрана, _showDatepicker попытается переместить его, поэтому верхний и левый угол будут разными, а marginTop, marginLeft может нуждаться в настройке.
monzonj

1
Я использовал аналогичный подход - я взял вашу идею использования beforeShow, но моя функция beforeShow использует эффект позиции JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(поскольку я использую altFieldопцию
datepicker

Это может работать для установки полей, но не работает для атрибутов «left», «top», «z-index» и «position».
aaronbauman

Насколько я понимаю, это тоже не работает, потому что jquery сбрасывает позицию после вызова beforeShow.
Software Engineer

Данный ответ является неправильной причиной DatePicker сбросит положение после beforeShow () вернулась.
whaefelinger

40

Я делаю это прямо в CSS:

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

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

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


Та же проблема, что и другой трюк css: работает только в том случае, если теперь вы точно указали, где должен быть указатель даты в CSS. Этот метод нельзя использовать для динамического размещения указателя даты. Пришлось использовать хак, привязку к inst.input.focus ()
Ааронбауман

У меня работал с использованием Bootstrap :), но я установил только свойство z-index.
Франсиско Гольденштейн

Бесполезен для чего-либо, кроме тривиальных реализаций, поскольку вы не будете знать, где находится поле ввода на странице.
Software Engineer

35

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

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

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

Код:

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

Спасибо @kottenator, это действительно полезно (особенно с position.js)!
Себастьян,

Эти ответы показывают не что иное, как достоинства position.js.
whaefelinger

Это все еще работает в v1.11.4, но это действительно грязный хакер, очень плохой API jQuery не позволяет нам делать это в afterShowметоде.
Skoua 01

29

Вот еще один вариант, который мне подходит: отрегулируйте 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="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<form>
<input class="datepicker" name="date1" type="text">
<input class="datepicker" name="date2" type="text">
</form>


Вау, это работает. Используя "inst.dpDiv.css (" top "," 40px! Important ");" не работает!
emeraldhieu

Далеко не идеален для решения программной проблемы с помощью тайм-аута.
whaefelinger

Спасибо, это сработало для меня, интересно, будет ли когда-нибудь мероприятие afterShow, это было бы здорово !! Но пока это помогает мне продолжать, несмотря ни на что: D
Роб Бранаган

16

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

 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

Во-первых, я думаю, что afterShowingв объекте datepicker должен быть метод, где вы могли бы изменить позицию после того, как jquery выполнил все свое вуду в _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 как настраиваемый элемент.
Алексей Комаров

3

Мне нужно было расположить datepicker в соответствии с родительским div, в котором находился мой элемент управления вводом без полей. Для этого я использовал утилиту "position", включенную в ядро ​​jquery UI. Я сделал это на мероприятии beforeShow. Как другие комментировали выше, вы не можете установить позицию непосредственно в beforeShow, так как код datepicker сбросит местоположение после завершения функции beforeShow. Чтобы обойти это, просто установите позицию с помощью setInterval. Текущий сценарий завершится, и появится указатель даты, а затем код изменения положения будет запущен сразу после того, как указатель даты станет видимым. Хотя этого никогда не должно происходить, но если указатель даты не отображается через 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);
        }

Очень некрасивое решение. Самая большая проблема - это заметный «скачок» виджета datepicker сразу после того, как он стал видимым, где внезапно срабатывает ваше «перемещение». Избегать любой ценой.
whaefelinger

2

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

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

2

Я исправил это с помощью собственного кода jquery.

  1. дал моему полю ввода datepicker класс " .datepicker2 "

  2. найти его текущее положение сверху и

  3. разместил всплывающее окно с именем класса " .ui-datepicker "

вот мой код.

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

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


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

1

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

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

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

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

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

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


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

Или вы можете использовать событие focus для объекта dateSelect и позиционирования api вместе. Вы можете поменять местами верх, низ и лево на правое или центральное (или действительно все, что вы хотите из позиции api). Таким образом, вам не нужен интервал или какое-либо безумно сложное решение, и вы можете настроить макет в соответствии со своими потребностями в зависимости от того, где находится ввод.

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

Лучший / самый правильный ответ !!
HirsuteJim

0

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

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

<!DOCTYPE html>

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


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

В 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;
    },

Это решение, по сути, правильное: введите свою собственную функцию _checkOffset () через jQuery.extend () и верните произвольный объект с числовыми свойствами «вверху» и «слева», то есть jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , смещение, isFixed) {return {top: mytop , left: myleft };}}); где mytop и myleft - по вашему вкусу, например, производные от inst .
whaefelinger

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

почему голосование? это не решает проблему? codepen.io/coconewty/pen/rajbNj
Джеймс

проголосовали? Потому что вы читали только заголовок вопроса и не приложили никаких усилий, чтобы разобраться в реальной проблеме. Просто предположите, что у вас есть два datepicker, прикрепленных к полям ввода разной ширины. Как ваше решение гарантирует, что левый край каждого виджета datepicker касается правого края поля ввода? С другой стороны, вы должны получить как минимум один балл за оригинальность ваших ответов.
whaefelinger

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.