Як змінити спливаюче положення керування jQuery DatePicker


109

Будь-яка ідея, як змусити DatePicker відображатися в кінці пов'язаного текстового поля замість прямо під ним? Як правило, це те, що текстове поле знаходиться внизу сторінки, а DatePicker зміщується вгору, щоб врахувати його і повністю охоплює текстове поле. Якщо користувач хоче ввести дату, а не вибрати її, він не може. Я вважаю за краще, щоб він з’явився відразу після текстового поля, тому не має значення, як він регулюється вертикально.

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


1
+1 за те, що ви не просто "зверталися" зі скаргою, що ваше рішення не є рішенням для D_N.
Леонідас

Відповіді:


20

Прийнята відповідь на це питання насправді не стосується вибору інтерфейсу jQuery UI Datepicker. Щоб змінити положення jQuery UI Datepicker, просто змініть .ui-datepicker у файлі css. Розмір Datepicker також можна змінити таким чином, просто відрегулюйте розмір шрифту.


4
Скажіть, будь ласка, скажіть, які зміни ви внесли?
Едді

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

64
Я поняття не маю, чому це прийнята відповідь, оскільки це майже повністю марно.
Програмний інженер

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
Хороший трюк. Проблема полягає в тому, що у випадках, коли вибір дату відображається за межами екрана, _showDatepicker намагатиметься перенести його, тому верхній і лівий буде різними, а marginTop, marginLeft може знадобитися налаштування.
Monzonj

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

Це може працювати для встановлення поля, але не вдається для атрибутів "зліва", "верх", "z-індекс" та "позиція".
aaronbauman

Як я розумію, це також не працює, тому що jquery скидає позицію після виклику beforeShow.
Програмний інженер

Даний відповідь є неправильною причиною DatePicker скине положення після beforeShow () повернулася.
whaefelinger

40

Я роблю це безпосередньо в CSS:

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

Поля мого введення дати всі 100 пікс. Я також додав z-індекс, так що календар також з’являється над спливаючими вікнами AJAX.

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


Те саме питання, що й інший css-трюк: працює лише в тому випадку, якщо ви зараз точно знаходите місце, де в програмі CSS повинен знаходитись вибір. Ви не можете використовувати цей метод для динамічного розміщення вибору дати. Мені довелося використовувати хак, прив’язуючи до inst.input.focus ()
aaronbauman

Працював для мене за допомогою Bootstrap :), але я встановлював лише властивість z-index.
Франциско Голденштейн

Марно для нічого, крім тривіальних реалізацій, оскільки ви не знатимете, де знаходиться поле введення на сторінці.
Програмний інженер

35

Ось моя зміна вирівнювання календаря Datepicker.

Я думаю, що це дуже приємно, адже ви можете керувати позиціонуванням через утиліту jQuery UI Position.

Одне обмеження: 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, це дуже корисно (особливо з позицією.js)!
Себастьян

Ці відповіді не показують нічого, крім достоїнств position.js.
whaefelinger

Це все ще працює в v1.11.4, але це справді брудний злом, занадто поганий API jQuery не дозволяє нам це робити afterShowметодом.
Skoua

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 (" верх "," 40px! Важливо ");" не працює!
смарагдовий

Далеко не ідеально для подолання програмної проблеми шляхом введення тайм-ауту.
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в об’єкті вибору дат повинен бути метод, де ви можете змінити позицію після того, як 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

Мені потрібно було розташувати підбирач дат відповідно до батьківського поділу, в якому знаходився мій контроль без вводу без поля. Для цього я використав утиліту "позиція", що входить до ядра інтерфейсу jquery. Я зробив це на заході раніше. Як зауважували інші, ви не можете встановити позицію безпосередньо у програмі beforeShow, оскільки код вибору дати скине місце розташування після завершення функції beforeShow. Щоб обійти це, просто встановіть позицію за допомогою setInterval. Поточний сценарій завершиться, показуючи панель вибору дати, а потім код перестановки запуститься одразу після того, як побачить датчик. Хоча це ніколи не ставатиметься, якщо вибирач дати не буде видно через .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

прив’язати фокусин після використання datepicker змінити css віджету побачення довідки

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

2

я виправив це за допомогою мого користувальницького коду jquery.

  1. надав моєму полі введення дату клас " .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 інтерфейс не налаштовано щось просте, щоб налаштувати це, як здається, досить велика проблема з календарем, що завжди спливає в певному положенні, значно далеко вниз від сторінки, до якої він додається.

У всякому разі, я хотів, щоб кінцеве рішення було достатньо загальним, щоб я міг його використовувати де завгодно, і воно спрацювало б. Здається, я нарешті дійшов висновку, що уникає деяких складніших і відповіді на відповідні 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());
});

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

Тестовано на 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

Або ви можете використовувати подію фокусування на об'єкті 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>

Використання перехідних моментів створює безлад. Сподіваємось, це заощадить когось деякий час у майбутньому.


0

Це додає функціональність до методу з назвою функція, що дозволяє вашому коду інкапсулювати його або для методу зробити 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 , offset, isFixed) {return {top: mytop , зліва: myleft };}}); де мітоп і мілефт на ваш особистий уподобання, наприклад, отримані з інст .
whaefelinger

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

чому голосуюче місто? не вирішує це питання? codepen.io/coconewty/pen/rajbNj
Джеймс

виборче місто? Тому що ви лише читали заголовок питання і не докладали жодних зусиль, щоб розібратися у реальній проблемі. Просто припустимо, що у вас є два вибірки дат, приєднаних до полів введення з різною шириною. Як ваше рішення забезпечує те, щоб лівий край кожного віджета датчика торкався правого краю поля введення? З іншого боку, ви повинні отримати хоча б один бал за оригінальність відповідей.
whaefelinger

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.