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

109

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

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

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

Ответы:

20

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

jonmc12
источник
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);
    }
})
Rost
источник
Спасибо @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может нарушить ваш код.

Monzonj
источник
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» - это мой ожидаемый пиксель, вы можете поменять его на свой.

sh6210
источник
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 приводит к беспорядку. Надеюсь, это кому-то сэкономит время в будущем.

Halfstop
источник
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
0
$('.PDatePicker').MdPersianDateTimePicker({
                Placement: 'top',          
            });
Хамед Хоссани
источник