So ändern Sie die Popup-Position des jQuery DatePicker-Steuerelements


109

Haben Sie eine Idee, wie Sie den DatePicker am Ende des zugehörigen Textfelds anstatt direkt darunter anzeigen können? In der Regel befindet sich das Textfeld am unteren Rand der Seite, und der DatePicker wird nach oben verschoben, um dies zu berücksichtigen, und deckt das Textfeld vollständig ab. Wenn der Benutzer das Datum eingeben möchte, anstatt es auszuwählen, kann er dies nicht. Ich möchte es lieber direkt hinter dem Textfeld anzeigen lassen, damit es keine Rolle spielt, wie es vertikal angepasst wird.

Irgendeine Idee, wie man die Positionierung steuert? Ich habe keine Einstellungen für das Widget gesehen und hatte kein Glück, die CSS-Einstellungen zu optimieren, aber ich könnte leicht etwas vermissen.


1
+1 für nicht nur das "Adressieren" der Beschwerde, dass Ihre Lösung nicht die Lösung für D_N ist.
Leonidas

Antworten:


20

Die akzeptierte Antwort auf diese Frage ist eigentlich nicht für den jQuery UI Datepicker. Um die Position des jQuery UI Datepickers zu ändern, ändern Sie einfach .ui-datepicker in der CSS-Datei. Auf diese Weise kann auch die Größe des Datepickers geändert werden. Passen Sie einfach die Schriftgröße an.


4
Könnten Sie mir bitte sagen, welche Änderungen Sie vorgenommen haben?
Wirbel

1
@gfrizzle - yep, meine Antwort war einfach so falsch. Endlich habe ich es geschafft. Keine Ahnung, woran ich damals dachte: /
Kev

64
Ich habe keine Ahnung, warum dies die akzeptierte Antwort ist, da sie fast völlig nutzlos ist.
Software Engineer

10
Die angegebene Antwort ist völlig nutzlos, da Datepicker das CSS von .ui-datepicker dynamisch ändert, bevor das Widget angezeigt wird.
Whaefelinger

4
Diese Antwort enthält keine Details und sollte nicht die akzeptierte Antwort sein.
Kapellensaft

120

Folgendes verwende ich:

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

Möglicherweise möchten Sie dem linken Rand auch etwas mehr hinzufügen, damit er nicht direkt im Eingabefeld angezeigt wird.


2
Guter Trick. Das Problem ist, dass in Fällen, in denen der Datepicker über die Bildschirmgrenzen hinaus angezeigt wird, der _showDatepicker versucht, ihn zu verschieben. Daher sind oben und links unterschiedlich und marginTop, marginLeft muss möglicherweise angepasst werden.
Monzonj

1
Ich habe einen ähnlichen Ansatz gewählt - ich habe Ihre Idee zur Verwendung von beforeShow aufgegriffen, aber meine beforeShow-Funktion verwendet den Positionseffekt von JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(da ich die altFieldOption des Datepickers für die Anzeige verwende)
Isaac Betesh

Dies funktioniert möglicherweise zum Festlegen von Rändern, schlägt jedoch für die Attribute "left", "top", "z-index" und "position" fehl.
Aaronbauman

Soweit ich weiß, funktioniert dies auch nicht, da jquery die Position nach dem Aufruf von beforeShow zurücksetzt.
Software Engineer

Die angegebene Antwort ist falsch, da der Datepicker die Position nach der Rückkehr von beforeShow () zurücksetzt.
Whaefelinger

40

Ich mache es direkt im CSS:

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

Meine Datumseingabefelder sind alle 100 Pixel breit. Ich habe auch den Z-Index hinzugefügt, damit der Kalender auch über AJAX-Popups angezeigt wird.

Ich ändere die CSS-Datei jquery-ui nicht. Ich überlade die Klasse in meiner CSS-Hauptdatei, damit ich das Thema ändern oder das Widget aktualisieren kann, ohne meine spezifischen Mods erneut eingeben zu müssen.


Gleiches Problem wie beim anderen CSS-Trick: Funktioniert nur, wenn Sie jetzt genau wissen, wo sich der Datepicker in CSS befinden soll. Mit dieser Methode können Sie den Datepicker nicht dynamisch platzieren. Ich musste einen Hack verwenden, der an inst.input.focus ()
aaronbauman

Hat bei mir mit Bootstrap funktioniert :), aber ich habe nur die Eigenschaft z-index festgelegt.
Francisco Goldenstein

Nutzlos für andere als triviale Implementierungen, da Sie nicht wissen, wo sich das Eingabefeld auf der Seite befindet.
Software Engineer

35

Hier ist meine Variante der Ausrichtung des Datepicker-Kalenders.

Ich finde es ziemlich schön, weil Sie die Positionierung über jQuery UI Position util steuern können.

Eine Einschränkung: jquery.ui.position.js erforderlich.

Code:

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

Vielen Dank an @kottenator, das ist wirklich nützlich (besonders mit position.js)!
Sebastian

Diese Antwort zeigt nichts weiter als die Vorzüge von position.js.
Whaefelinger

Dies funktioniert immer noch in Version 1.11.4, aber dies ist in der Tat ein schmutziger Hack. Schade, dass die jQuery-API dies nicht in einer afterShowMethode zulässt .
Skoua

29

Hier ist eine weitere Variante, die für mich gut funktioniert: Passen Sie das Rect.top + 40 und das Rect.left + 0 an Ihre Bedürfnisse an:

$(".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 es funktioniert. Verwenden von "inst.dpDiv.css (" top "," 40px! Important ");" funktioniert nicht!
Smaragdhieu

Weit davon entfernt, ein programmatisches Problem durch die Einführung eines Timeouts zu überwinden.
Whaefelinger

Danke, das hat bei mir funktioniert, ich frage mich, ob es jemals ein AfterShow-Event geben wird, das wäre großartig !! Aber
trotzdem

16

Das funktioniert bei mir:

 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

Zuerst denke ich, dass es eine afterShowingMethode im Datepicker-Objekt geben sollte, mit der Sie die Position ändern können, nachdem jquery alle Voodoos in der _showDatepickerMethode ausgeführt hat. Darüber hinaus preferedPositionwäre auch ein aufgerufener Parameter wünschenswert, sodass Sie ihn festlegen und abfragen können, falls der Dialog außerhalb des Ansichtsfensters gerendert wird.

Es gibt einen "Trick", um dieses letzte Ding zu machen. Wenn Sie die _showDatepickerMethode studieren , werden Sie die Verwendung einer privaten Variablen sehen $.datepikcer._pos. Diese Variable wird eingerichtet, wenn sie noch niemand eingerichtet hat. Wenn Sie diese Variable ändern, bevor das Dialogfeld angezeigt wird, übernimmt Jquery sie und versucht, das Dialogfeld an dieser Position zuzuweisen. Wenn es außerhalb des Bildschirms gerendert wird, wird es angepasst, um sicherzustellen, dass es sichtbar ist. Hört sich gut an, oder?

Das Problem ist; _posist privat, aber wenn dir das nichts ausmacht. Sie können:

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

Achten Sie jedoch auf Jquery-ui-Updates, da eine Änderung in der internen Implementierung von _showDatepickermöglicherweise Ihren Code beschädigt .


1
Sie hätten dies in der jQuery-Benutzeroberfläche als konfigurierbares Element hinzufügen sollen.
Aleksej Komarov

3

Ich musste den Datepicker gemäß einem übergeordneten Div positionieren, in dem sich meine randlose Eingabesteuerung befand. Dazu habe ich das Dienstprogramm "position" verwendet, das im Kern der jquery-Benutzeroberfläche enthalten ist. Ich habe das im beforeShow-Event gemacht. Wie andere oben kommentiert haben, können Sie die Position nicht direkt in beforeShow festlegen, da der Datepicker-Code den Speicherort nach Abschluss der beforeShow-Funktion zurücksetzt. Um dies zu umgehen, legen Sie die Position einfach mit setInterval fest. Das aktuelle Skript wird abgeschlossen und zeigt den Datepicker an. Anschließend wird der Neupositionierungscode sofort ausgeführt, nachdem der Datepicker sichtbar ist. Obwohl es niemals passieren sollte, wenn der Datums-Picker nach 0,5 Sekunden nicht sichtbar ist, hat der Code eine Ausfallsicherheit, um das Intervall aufzugeben und zu löschen.

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

Sehr hässliche Lösung. Das größte Problem wäre ein merklicher "Sprung" des Datepicker-Widgets, kurz nachdem es sichtbar wurde, wo plötzlich Ihr "Umzug" einsetzt. Um jeden Preis zu vermeiden.
Whaefelinger

2

Binden Sie den Fokus, nachdem Sie Datepicker verwendet haben. Ändern Sie die CSS des Widgets von Datepicker

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

2

Ich habe es mit meinem benutzerdefinierten JQuery-Code behoben.

  1. gab meinem Datepicker-Eingabefeld eine Klasse " .datepicker2 "

  2. Finden Sie die aktuelle Position von oben und

  3. positionierte das Popup-Feld, dessen Klassenname " .ui-datepicker " ist.

Hier ist mein Code.

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

hier ist "40" mein erwartetes Pixel, Sie können mit Ihrem ändern.


1

Fix Show Position Problem 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

Eine sehr einfache Abfragefunktion.

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

1

Ich habe lächerlich viel Zeit damit verbracht, dieses Problem für mehrere Seiten einer neuen Site herauszufinden, die ich entwickle, und nichts schien zu funktionieren (einschließlich einer der verschiedenen oben vorgestellten Lösungen, die ich implementiert habe. Ich vermute, jQuery hat sich gerade geändert Ich weiß nicht, ob die Lösungen nicht mehr funktionieren. Ehrlich gesagt verstehe ich nicht, warum in der jQuery-Benutzeroberfläche nicht einfach etwas implementiert ist, um dies so zu konfigurieren, wie es scheint Ein ziemlich großes Problem, bei dem der Kalender immer an einer Position weit unten auf der Seite von der Eingabe auftaucht, an die er angehängt ist.

Jedenfalls wollte ich eine Endlösung, die generisch genug war, dass ich sie überall verwenden konnte und sie funktionieren würde. Ich scheine endlich zu einem Schluss gekommen zu sein, der einige der komplizierteren und jQuery-Code-spezifischen Antworten oben vermeidet:

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

Im Wesentlichen füge ich vor jedem Datepicker-Show-Ereignis ein neues Style-Tag am Kopf hinzu (lösche das vorherige, falls vorhanden). Diese Methode umgeht die meisten Probleme, auf die ich während der Entwicklung gestoßen bin.

Getestet auf Chrome, Firefox, Safari und IE> 8 (da IE8 mit jsFiddle nicht gut funktioniert und ich meine Begeisterung für das Sorgen verliere

Ich weiß, dass dies eine Mischung aus jQuery- und Javascript-Kontexten ist, aber an dieser Stelle möchte ich mich einfach nicht darum bemühen, es in jQuery zu konvertieren. Wäre einfach, ich weiß. Ich bin gerade so fertig mit diesem Ding. Hoffe, jemand anderes kann von dieser Lösung profitieren.


1

Sie haben den Klassennamen in geändert ui-datepicker-trigger

Das funktioniert also in jquery 1.11.x

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


1

Oder Sie können das Fokusereignis für Ihr dateSelect-Objekt verwenden und die API zusammen positionieren. Sie können oben und unten und links gegen rechts oder in der Mitte tauschen (oder wirklich alles, was Sie von der Positions-API wollen). Auf diese Weise benötigen Sie kein Intervall oder eine wahnsinnig komplexe Lösung und können das Layout je nach Eingangsort entsprechend Ihren Anforderungen konfigurieren.

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

DIE beste / richtigste Antwort !!
HirsuteJim

0

Es ist auch erwähnenswert, dass Ihre jQuery-UI-Komponenten und andere Elemente falsch positioniert werden, wenn der IE in den Quirks-Modus fällt.

Um sicherzustellen, dass Sie nicht in den Mackenmodus geraten, stellen Sie sicher, dass Sie Ihren Doctype korrekt auf den neuesten HTML5-Code eingestellt haben.

<!DOCTYPE html>

Die Verwendung von Transitional bringt die Dinge durcheinander. Hoffentlich spart dies jemandem in Zukunft etwas Zeit.


0

Dadurch wird die Funktionalität in eine Methode mit dem Namen function eingefügt, sodass Ihr Code sie kapseln oder die Methode zu einer jquery-Erweiterung machen kann. Nur für meinen Code verwendet, funktioniert perfekt

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

Aktualisieren Sie in Jquery.UI einfach die Funktion _checkOffset, sodass viewHeight zu offset.top hinzugefügt wird, bevor offset zurückgegeben wird.

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

Diese Lösung ist im Wesentlichen korrekt: Fügen Sie Ihre eigene Funktion _checkOffset () über jQuery.extend () ein und geben Sie ein beliebiges Objekt mit den numerischen Eigenschaften "top" und "left" zurück, dh jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); wo mytop und myleft nach Ihrem persönlichen Geschmack sind, zum Beispiel abgeleitet von inst .
Whaefelinger

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

warum die Abstimmung? Behebt dies nicht das Problem? codepen.io/coconewty/pen/rajbNj
James

Gefällt mir nicht? Weil Sie nur den Titel der Frage gelesen haben und sich keine Mühe gegeben haben, sich mit dem eigentlichen Problem auseinanderzusetzen. Nehmen Sie einfach an, dass Sie zwei Eingabefelder an Eingabefelder mit unterschiedlichen Breiten angehängt haben. Wie stellt Ihre Lösung sicher, dass der linke Rand jedes Datepicker-Widgets den rechten Rand des Eingabefelds berührt? Auf der anderen Seite sollten Sie mindestens einen Punkt für die Originalität Ihrer Antworten erhalten.
Whaefelinger

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.