Jak zmienić pozycję wyskakującego okienka kontrolki jQuery DatePicker


109

Masz pomysł, jak sprawić, by DatePicker pojawiał się na końcu skojarzonego pola tekstowego zamiast bezpośrednio pod nim? Zwykle zdarza się, że pole tekstowe znajduje się na dole strony, a DatePicker przesuwa się w górę, aby to uwzględnić i całkowicie zakrywa pole tekstowe. Jeśli użytkownik chce wpisać datę zamiast ją wybrać, nie może. Wolałbym, aby pojawiał się tuż za polem tekstowym, więc nie ma znaczenia, jak dopasowuje się w pionie.

Masz pomysł, jak kontrolować pozycjonowanie? Nie widziałem żadnych ustawień widżetu i nie miałem szczęścia modyfikować ustawień CSS, ale łatwo mogłem czegoś przegapić.


1
+1 za nie tylko „zajęcie się” skargą, że Twoje rozwiązanie nie jest rozwiązaniem dla D_N.
Leonidas,

Odpowiedzi:


20

Przyjęta odpowiedź na to pytanie w rzeczywistości nie dotyczy Datepicker interfejsu użytkownika jQuery. Aby zmienić położenie Datepicker jQuery UI, wystarczy zmodyfikować .ui-datepicker w pliku css. Rozmiar Datepicker można również zmienić w ten sposób, wystarczy dostosować rozmiar czcionki.


4
Czy możesz mi powiedzieć, jakie zmiany wprowadziłeś?
eddy

1
@gfrizzle - tak, moja odpowiedź była tak zła. Wreszcie zabrałem się za umieszczenie go w koszu. Nie mam pojęcia, o czym wtedy myślałem: /
Kev

64
Nie mam pojęcia, dlaczego jest to akceptowana odpowiedź, ponieważ jest prawie całkowicie bezużyteczna.
Inżynier oprogramowania,

10
Podana odpowiedź jest całkowicie bezużyteczna, ponieważ datepicker dynamicznie modyfikuje css .ui-datepicker przed wyświetleniem widgetu.
whaefelinger

4
Ta odpowiedź nie zawiera żadnych szczegółów i nie powinna być akceptowaną odpowiedzią.
chapeljuice

120

Oto czego używam:

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

Możesz też chcieć dodać trochę więcej do lewego marginesu, aby nie było dokładnie naprzeciw pola wprowadzania.


2
Dobry trik. Problem polega na tym, że w przypadkach, gdy datepicker jest wyświetlany poza granicami ekranu, _showDatepicker spróbuje go przenieść, dlatego góra i lewo będą inne, a marginTop, marginLeft może wymagać dostrojenia.
monzonj

1
Użyłem podobnego podejścia - przyjąłem twój pomysł użycia beforeShow, ale moja funkcja beforeShow wykorzystuje efekt pozycji JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(ponieważ używam altFieldopcji datepicker do wyświetlania)
Isaac Betesh

Może to działać przy ustawianiu marginesów, ale kończy się niepowodzeniem w przypadku atrybutów „lewy”, „górny”, „z-index” i „pozycja”.
aaronbauman

Jak rozumiem, to też nie działa, ponieważ jquery resetuje pozycję po wywołaniu beforeShow.
Inżynier oprogramowania,

Podana odpowiedź jest zła, ponieważ datepicker zresetuje pozycję po zwróceniu funkcji beforeShow ().
whaefelinger

40

Robię to bezpośrednio w CSS:

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

Moje pola wprowadzania daty mają szerokość 100 pikseli. Dodałem również indeks z, więc kalendarz pojawia się również nad wyskakującymi okienkami AJAX.

Nie modyfikuję pliku CSS jquery-ui; Przeciążam klasę w moim głównym pliku CSS, więc mogę zmienić motyw lub zaktualizować widżet bez konieczności ponownego wprowadzania moich konkretnych modów.


Ten sam problem, co w przypadku innej sztuczki css: działa tylko wtedy, gdy w CSS dokładnie znajduje się datapicker. Nie można użyć tej metody do dynamicznego umieszczania selektora dat. Musiałem użyć hacka, wiążąc się z inst.input.focus ()
aaronbauman

Pracowałem dla mnie używając Bootstrap :), ale ustawiam tylko właściwość z-index.
Francisco Goldenstein

Bezużyteczne do niczego innego niż trywialne implementacje, ponieważ nie wiesz, gdzie znajduje się pole wejściowe na stronie.
Inżynier oprogramowania,

35

Oto moja odmiana wyrównywania kalendarza Datepicker.

Myślę, że to całkiem fajne, ponieważ możesz kontrolować pozycjonowanie za pomocą narzędzia jQuery UI Position.

Jedno ograniczenie: wymagany plik jquery.ui.position.js.

Kod:

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

Dziękuję @kottenator, jest to naprawdę przydatne (szczególnie w przypadku position.js)!
Sebastian,

Ta odpowiedź ukazuje jedynie zalety position.js.
whaefelinger

To nadal działa w wersji 1.11.4, ale to rzeczywiście brudny hack, szkoda, że ​​API jQuery nie pozwala nam tego zrobić w afterShowmetodzie.
Skoua

29

Oto kolejna wariacja, która działa dobrze dla mnie, dostosuj prawy górny + 40, prawy lewy + 0 do swoich potrzeb:

$(".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>


Wow, to działa. Korzystanie z „inst.dpDiv.css („ do góry ”,„ 40px! Ważne ”);” nie działa!
emeraldhieu

Daleko od doskonałości w pokonywaniu problemu programowego poprzez wprowadzenie limitu czasu.
whaefelinger

Dziękuję, że to zadziałało, zastanawiam się, czy kiedykolwiek będzie impreza afterShow, byłoby wspaniale !! Ale na razie pomaga mi to kontynuować bez względu na: D
Rob Branaghan

16

To działa dla mnie:

 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

Po pierwsze, myślę, że afterShowingw obiekcie datepicker powinna znajdować się metoda, w której można by zmienić pozycję po tym, jak jquery wykona całe swoje voodoo w _showDatepickermetodzie. Dodatkowo preferedPositionpożądany byłby również parametr o nazwie , więc można by go ustawić i zmodyfikować jquery w przypadku, gdy okno dialogowe jest renderowane poza rzutnią.

Jest pewna sztuczka, aby zrobić ostatnią rzecz. Jeśli przestudiujesz tę _showDatepickermetodę, zobaczysz użycie zmiennej prywatnej $.datepikcer._pos. Ta zmienna zostanie ustawiona, jeśli nikt wcześniej jej nie ustawił. Jeśli zmodyfikujesz tę zmienną przed wyświetleniem okna dialogowego, Jquery weźmie ją i spróbuje przydzielić okno dialogowe w tej pozycji, a jeśli wyrenderuje się poza ekranem, dostosuje je, aby upewnić się, że jest widoczne. Brzmi nieźle, co?

Rzecz w tym; _posjest prywatny, ale jeśli nie masz nic przeciwko temu. Możesz:

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

Uważaj jednak na aktualizacje Jquery-ui, ponieważ zmiana w wewnętrznej implementacji _showDatepickermoże spowodować uszkodzenie kodu.


1
Powinni dodać to w interfejsie użytkownika jQuery jako element konfigurowalny.
Aleksej Komarov

3

Musiałem ustawić datepicker zgodnie z nadrzędnym elementem div, w którym znajdowała się moja kontrola danych wejściowych bez obramowania. Aby to zrobić, użyłem narzędzia „position” zawartego w rdzeniu interfejsu użytkownika jquery. Zrobiłem to podczas wydarzenia beforeShow. Jak skomentowali inni powyżej, nie można ustawić pozycji bezpośrednio w beforeShow, ponieważ kod datepicker zresetuje lokalizację po zakończeniu funkcji beforeShow. Aby to obejść, po prostu ustaw pozycję za pomocą setInterval. Bieżący skrypt zakończy działanie, pokazując datepicker, a następnie kod repozycjonowania zostanie uruchomiony natychmiast po wyświetleniu datepicker. Chociaż nigdy nie powinno się to zdarzyć, jeśli datapicker nie jest widoczny po 0,5 sekundach, kod jest odporny na awarie, aby zrezygnować i wyczyścić interwał.

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

Bardzo brzydkie rozwiązanie. Największym problemem byłby zauważalny „skok” widżetu datepicker zaraz po tym, jak stał się on widoczny w miejscu, gdzie nagle pojawia się „relokacja”. Należy tego unikać za wszelką cenę.
whaefelinger

2

bind focusin po użyciu datepicker zmiana css widgetu datepicker'a życzę pomocy

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

2

naprawiłem to za pomocą mojego niestandardowego kodu jQuery.

  1. nadałem mojemu polu wejściowemu Datepicker klasę „ .datepicker2

  2. znaleźć aktualną pozycję od góry i

  3. umieścił wyskakujące okienko, którego nazwa klasy to „ .ui-datepicker

oto mój kod.

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

tutaj "40" to mój oczekiwany piksel, możesz zmienić swój.


1

napraw problem z pozycją pokazu 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

Bardzo prosta funkcja jquery.

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

1

Spędziłem absurdalnie dużo czasu próbując rozwiązać ten problem przez kilka stron nowej witryny, którą tworzę i nic nie wydawało się działać (w tym dowolne z różnych rozwiązań przedstawionych powyżej, które wdrożyłem. Zgaduję, że jQuery właśnie się zmieniło wystarczająco dużo, ponieważ zasugerowano, że rozwiązania już nie działają. Nie wiem. Szczerze mówiąc, nie rozumiem, dlaczego nie ma czegoś prostego zaimplementowanego w interfejsie użytkownika jQuery, aby to skonfigurować, jak się wydaje dość duży problem polegający na tym, że kalendarz zawsze pojawia się w jakimś miejscu znacznie daleko w dół strony od wejścia, do którego jest dołączony.

W każdym razie chciałem rozwiązania końcowego, które byłoby na tyle ogólne, że mógłbym go używać wszędzie i zadziałałoby. Wydaje się, że w końcu doszedłem do wniosku, który pozwala uniknąć niektórych z bardziej skomplikowanych i specyficznych dla kodu jQuery odpowiedzi powyżej:

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

Zasadniczo dołączam nowy tag stylu do głowy przed każdym zdarzeniem „show” datepicker (usuwanie poprzedniego, jeśli jest obecny). Ta metoda robienia rzeczy pozwala obejść większość problemów, które napotkałem podczas programowania.

Testowane na Chrome, Firefox, Safari i IE> 8 (ponieważ IE8 nie działa dobrze z jsFiddle i tracę zamiłowanie do dbania o

Wiem, że jest to mieszanka kontekstów jQuery i javascript, ale w tym momencie po prostu nie chcę wkładać wysiłku w konwersję go do jQuery. Wiem, byłoby proste. Skończyłem z tym teraz. Mam nadzieję, że ktoś inny może skorzystać z tego rozwiązania.


1

Zmienili nazwę klasy na ui-datepicker-trigger

Więc to działa jquery 1.11.x

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


1

Możesz też użyć zdarzenia focus na swoim obiekcie dateSelect i jednocześnie umieścić api. Możesz zamienić górną i dolną oraz lewą stronę na prawą lub środkową (lub naprawdę cokolwiek chcesz z api pozycji). W ten sposób nie potrzebujesz interwału ani niewiarygodnie złożonego rozwiązania i możesz skonfigurować układ tak, aby odpowiadał Twoim potrzebom w zależności od tego, gdzie jest wejście.

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

NAJLEPSZA / Najbardziej poprawna odpowiedź !!
HirsuteJim

0

Warto również zauważyć, że jeśli IE wpadnie w tryb dziwactw, komponenty interfejsu użytkownika jQuery i inne elementy zostaną niepoprawnie ustawione.

Aby upewnić się, że nie wpadniesz w tryb dziwactw, upewnij się, że poprawnie ustawiłeś swój doctype na najnowszy HTML5.

<!DOCTYPE html>

Korzystanie z trybu przejściowego powoduje bałagan. Mam nadzieję, że pozwoli to komuś zaoszczędzić trochę czasu w przyszłości.


0

Umieszcza to funkcjonalność w metodzie o nazwie function, umożliwiając kodowi jej hermetyzację lub przekształcenie metody w rozszerzenie jquery. Po prostu użyty w moim kodzie, działa idealnie

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

W Jquery.UI po prostu zaktualizuj funkcję _checkOffset, tak aby parametr viewHeight był dodawany do offset.top, zanim zostanie zwrócone przesunięcie.

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

To rozwiązanie jest w zasadzie poprawne: wstrzyknij własną funkcję _checkOffset () za pośrednictwem jQuery.extend () i zwróć dowolny obiekt mający właściwości numeryczne „top” i „left”, np. JQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); gdzie mytop i myleft są według twoich osobistych upodobań, na przykład pochodzące z inst .
whaefelinger

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

dlaczego głosowano? czy to nie rozwiązuje problemu? codepen.io/coconewty/pen/rajbNj
James

zagłosowany? Ponieważ czytałeś tylko tytuł pytania i nie próbowałeś zgłębiać prawdziwego problemu. Po prostu załóżmy, że masz dwa datepicker dołączone do pól wejściowych o różnych szerokościach. W jaki sposób Twoje rozwiązanie zapewnia, że ​​lewa krawędź widżetu DatePicker dotyka prawej krawędzi pola wejściowego? Z drugiej strony powinieneś otrzymać przynajmniej jeden punkt za oryginalność swoich odpowiedzi.
whaefelinger

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.