2009-11-30 14 views
30

Der Datepicker in jQueryUI wird mit einer dynamischen Position gerendert. Es rendert entsprechend seiner CSS, wenn es genug Platz dafür gibt, aber wenn es nicht genügend Fensterplatz gibt, versucht es, auf Bildschirm zu übertragen. Ich brauche es, um jedes Mal am selben Ort zu bleiben und zu rendern, unabhängig von der Bildschirmposition oder anderen Umständen. Wie kann das mit dem jQueryUI Datepicker gemacht werden? Andere Implementierungen von jQuery datepicker scheinen Möglichkeiten zu haben, dies zu tun, aber ich sehe keinen Weg, dies für die UI-Version zu tun.So steuern Sie die Positionierung von jQueryUI datepicker

Die Antwort scheint nicht nur die CSS modifiziert zu werden:

.ui-datepicker { width: 17em; padding: .2em .2em 0; (trying top/margin-top/position:relative, etc. here...)} 

... da, wenn die Datepicker wird dynamisch erstellt schafft oben und im Element Stil links. Hab noch keinen Weg gefunden. Ein Ansatz, den ich sah, ist so etwas wie dies in der beforeShow Option zu geben:

beforeShow: function(input,inst){ 
           inst.dpDiv.css({ 
            'top': input.offsetHeight+ 'px', 
            'left':(input.offsetWidth - input.width)+ 'px' 
               }); 
           } 

Dies hat eine gewisse Wirkung, aber die oberen und linken Eigenschaften werden noch dynamisch danach eingestellt werden ausgeführt, wenn die Datumsauswahl macht. Es versucht immer noch, auf dem Bildschirm zu rendern. Wie bekomme ich es immer an der gleichen Stelle zu rendern? Mein nächster Schritt ist wahrscheinlich, in die datepicker Eingeweide zu gehen und Dinge herauszuziehen. Irgendwelche Ideen?

Beachten Sie, dass die Antwort (für die UI-Version) ist nicht in:

Antwort

60

Dies in der Hoffnung, dass es anderen helfen wird. Zumindest ab v1.8.1 von datepicker funktioniert die Verwendung von 'window.DP_jQuery.datepicker' nicht mehr, weil der Zeiger (rechte Bezeichnung?) Jetzt mit einem Zeitstempel seiner Erstellung benannt ist - also zum Beispiel jetzt 'window'. DP_jQuery_1273700460448 '. So, jetzt, anstatt den Zeiger auf das Objekt Datepicker verwenden, lesen Sie es direkt wie folgt aus:

$.extend($.datepicker,{_checkOffset:function(inst,offset,isFixed){return offset}}); 

Vielen Dank für die Antwort unten für mich zu bekommen, was ich brauchte.

+0

Kein Problem - Ich bin glücklich, jemand anderes hat etwas daraus, ich erinnere mich, verbringen eine oder zwei Stunden herauszufinden, dies aus. – Purrell

+0

Das funktioniert ein Vergnügen! –

+1

Nice one, hat mir wirklich geholfen! Für jeden, der es braucht, können Sie dann die Ränder des Datepickers wie folgt ändern: .ui-datepicker {margin-left: -361px; } – bbeckford

9

Edit: JaredC gab eine aktualisierte Antwort für spätere Versionen von jQuery oben . Antwort darauf umschalten.

In Ordnung, dies ist eine Frage der Monkeypatching der Funktion, die es versucht, immer im Ansichtsfenster zu rendern, da keine Option zum Aktivieren/Deaktivieren der Funktion zur Verfügung gestellt wird. Zum Glück ist es in einer Funktion abgekoppelt und isoliert, so dass wir einfach hineingehen und es außer Kraft setzen können. Der folgende Code vollständig deaktiviert diese Funktion nur:

$.extend(window.DP_jQuery.datepicker,{_checkOffset:function(inst,offset,isFixed){return offset}}); 

_checkOffset wird aufgerufen, wenn es zu öffnen und es tut Berechnungen auf der Offset und gibt einen neuen Offset, wenn es sonst außerhalb der Sichtöffnung wäre. Dies ersetzt den Funktionskörper, um den ursprünglichen Offset einfach durchzulassen. Dann können Sie den beforeShow-Einstellungs-Hack und/oder die .ui-datepicker-css-Klasse verwenden, um sie dort einzufügen, wo Sie möchten.

1

in Ihrer CSS-Datei, zum Beispiel:

#ui-datepicker-div { 
    position: absolute !important; 
    top: auto !important; 
    left: auto !important; 
} 

Ihre wichtigen Einstellungen, was auch immer sie sind, wird die Inline-Standardwerte außer Kraft setzen.

+2

das ist falsch, Inline-Stile haben immer Priorität – hcharge

+2

@ hcharge tatsächlich, sie nicht, wenn Sie verwenden, wichtig in der CSS-Stil. Nur Inline-Styles, die selbst wichtig sind, können dann das! Wichtige, das von CSS kommt, überschreiben - http://jsfiddle.net/NTCP7/ – Katai

+0

Während '! Wichtig 'ein bisschen ein CSS-Hack des letzten Ausweges ist, funktioniert diese Lösung gut und ist am einfachsten zu implementieren. –

-1

Hier ist eine einfachere Lösung

var $picker = $(".myspanclass").datepicker(); // span has display: inline-block 
$picker.find('.ui-datepicker').css('margin-left', '-50px'); 
+0

Diese Antwort ist falsch, weil der Thread ganz speziell nach einem statischen Render-Speicherort gefragt wurde. Ihre Antwort verschiebt einfach die Position 50px nach links. – whaefelinger

6

binden focusin nach datepicker Änderung css von datepicker`s Widget Wunsch Hilfe

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

wenn Sie bereits eine Antwort akzeptiert sehen, was ist der Punkt in der Antwort wieder. Wie auch immer, Willkommen bei SO! :) – LGAP

+0

Wie man es ohne "Hack" macht, ist immer eine Sache. Accepted solution ** (Überschreiben der internen 'privaten' Logik von datepicker) ** kann diesen Fix mit jeder neuen Version von jquery.ui brechen. Betrachtet man die akzeptierte Antwort, scheint es mir tatsächlich so zu sein ... – CodeLama

1

früher mit i oben versucht zu geben, nach links in beforeShow Veranstaltung von datepicker.js, das wird durch die _showDatePicker-Methode von jquery-ui-custom.js überschrieben. Aber nach dem Timeout funktioniert das Fenster gut. Unten ist der Code

beforeShow : function(input,inst) { 
    var offset = js.select("#" + dpId).offset(); 
         var height = js.select("#" + dpId).height(); 
         var width = js.select("#" + dpId).width(); 
         window.setTimeout(function() { 
           js.select(inst.dpDiv).css({ top: (offset.top + height - 185) + 'px', left: (offset.left + width + 50) + 'px' }) 
         }, 1); 
} 
+1

Diese Lösung ist nichts anderes als ein Hack. Obwohl es im Allgemeinen funktioniert, bemerken Sie vielleicht eine Art "Sprung" auf dem Datepicker-Widget, besonders wenn die von Datepicker erzeugte Position weit von Ihrer "gehackten" Position entfernt ist. Dies ist natürlich nur sekundär, da Ihre Lösung auf "langsamen" Computern möglicherweise überhaupt nicht funktioniert. – whaefelinger

-1

der Kalender der Datumsauswahl war Anzeige auf der oberen rechten meiner Eingabefeld, so dass die Spitze davon wurde ausgeblendet von meiner Menüleiste standardmäßig. Hier ist, wie ich das Widget positioniert (jquery-ui-Version 1.11.4) sehr einfach (beachten Sie, dass ‚ui-Datepicker‘ ist der Klassenname von jquery-ui angegeben):

$(document).ready(function() { 
$(".ui-datepicker").css('margin-left', '-50px', 'margin-top', '-50px'); 
//... 
} 
+0

Ihr Problem vermisst eine Korrelation mit dem angegebenen Problem dieses Threads. Zweitens, warum CSS-Eigenschaften über JS und nicht über CSS-Stylesheets anwenden? – whaefelinger

1

Dies ist eine ganz alte Frage jedoch Ich bin kürzlich auf ein ähnliches Problem mit dem jQuery UI Datepicker gestoßen. Wir haben bereits die oben von @ JaredC veröffentlichte Lösung verwendet (speziell dieses Code-Snippet: $.extend($.datepicker,{_checkOffset:function(inst,offset,isFixed){return offset}});), aber es würde nicht für ein Modal funktionieren, das eine Eingabe hatte, in der wir ein Dropdown-Menü rendern mussten.

Dieses Problem tritt auf, weil beim Scrollen der Seite der Offset der Eingabe in den modalen Änderungen relativ zum oberen Rand der gescrollten Seite auftritt. Das resultierende Verhalten würde bedeuten, dass der Datapicker in einer anderen vertikalen Position gerendert würde, je nachdem, wie weit Sie die Seite herunterscrollen (Anmerkung: während der Datapicker sichtbar und scrollen war, war er bereits fixiert). Die Lösung für dieses Problem ("datepicker Eingang verschachtelt in einem Modal") besteht darin, stattdessen die vertikale Positionierung der Eingabe relativ zum Ansichtsbildschirm zu berechnen und dann die Höhe der Eingabe hinzuzufügen (erlaubt die "top" css Eigenschaft des Datepickers) direkt unter dem der Eingabe liegen).

Das folgende Snippet ist in coffeescript. Anstatt den regulären Offset nach @ JaredCs Lösung zurückzugeben, erhalten wir stattdessen die elementId der Eingabe vom Objekt 'inst' und greifen dann über jquery auf das Objekt zu, um daraus den Abstand der Eingabe vom oberen Bildschirmrand zu berechnen das Ansichtsfenster.

# CoffeeScript 
$.extend($.datepicker, { _checkOffset: (inst,offset,isFixed) -> 
     offset.top = $("##{inst.id}").offset().top - $(window).scrollTop() + $("##{inst.id}")[0].getBoundingClientRect().height 
     offset 
    } 
) 

// JavaScript 
$.extend($.datepicker, { 
    _checkOffset: function(inst, offset, isFixed) { 
     offset.top = $("#" + inst.id).offset().top - $(window).scrollTop() + $("#" + inst.id)[0].getBoundingClientRect().height; 
     return offset; 
    } 
}); 
+0

Ihr Kaffee ist mit Syntaxfehlern gespickt. Würde es dir etwas ausmachen, sie zu reparieren? Oder besser, transpilieren Sie es für uns zu JS? ** Bearbeiten: ** Nvm, SO hat nur den Abstand vermasselt. Deshalb hasse ich Leerzeichen-abhängige Sprachen. Ich ändere deine Antwort mit dem JS, hoffe, das ist OK. – mpen

1

Das Problem wurde I ist mit, dass die Datumsauswahl falsch Inneren feste Elemente angeordnet ist, wie beispielsweise ausgefallene/Leuchtkästen. Aus irgendeinem Grund wechselt der Datepicker dann in den "fixierten" Positionierungsmodus, und dann wird die Offsetberechnung falsch, wenn die absolute Positionierung gut funktioniert hätte.

Allerdings können wir die richtige Feststellung mit diesem Hack erhalten:

const checkOffset = $.datepicker._checkOffset; 

$.extend($.datepicker, { 
    _checkOffset: function(inst, offset, isFixed) { 
     if(!isFixed) { 
      return checkOffset.apply(this, arguments); 
     } 

     let isRTL = this._get(inst, "isRTL"); 
     let obj = inst.input[0]; 

     while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { 
      obj = obj[isRTL ? "previousSibling" : "nextSibling"]; 
     } 

     let rect = obj.getBoundingClientRect(); 

     return { 
      top: rect.top, 
      left: rect.left, 
     }; 
    } 
}); 
1

mit jQuery:

beforeShow : function(input,inst){ 
    var offset = $(input).offset(); 
    var height = $(input).height(); 
    window.setTimeout(function() { 
     $(inst.dpDiv).css({ top: (offset.top + height) + 'px', left:offset.left + 'px' }) 
    }, 1); 
} 
+0

Ich fand dies am nützlichsten mit den neuesten jQuery UI-Versionen –

1

Die akzeptierte Antwort insgesamt sehr gut funktioniert.

Allerdings hatte ich mit jQuery UI v1.11.4 ein Problem, bei dem sich der Datepicker in einem modalen Fenster (fixierte Positionierung) von der Eingabe wegstellte, wenn das Browserfenster nach unten gescrollt wurde.Ich war in der Lage, dieses Problem zu beheben Bearbeitung der angenommenen Antwort wie folgt:

const checkOffset = $.datepicker._checkOffset; 

$.extend($.datepicker, { 
    _checkOffset: function(inst, offset, isFixed) { 
    if(isFixed) { 
     return checkOffset.apply(this, arguments); 
    } else { 
     return offset; 
    } 
    } 
}); 
Verwandte Themen