Come modificare la posizione del popup del controllo jQuery DatePicker


109

Qualche idea su come far apparire il DatePicker alla fine della casella di testo associata invece che direttamente sotto di essa? Quello che tende ad accadere è che la casella di testo si trova verso la parte inferiore della pagina e DatePicker si sposta verso l'alto per tenerne conto e copre completamente la casella di testo. Se l'utente desidera digitare la data invece di selezionarla, non può. Preferisco che appaia subito dopo la casella di testo, quindi non importa come si regola verticalmente.

Qualche idea su come controllare il posizionamento? Non ho visto alcuna impostazione per il widget e non ho avuto fortuna a modificare le impostazioni CSS, ma potrei facilmente perdere qualcosa.


1
+1 per non solo "indirizzare" il reclamo, che la tua soluzione non è la soluzione per D_N.
Leonida

Risposte:


20

La risposta accettata per questa domanda non è in realtà per il Datepicker dell'interfaccia utente jQuery. Per cambiare la posizione del Datepicker dell'interfaccia utente jQuery basta modificare .ui-datepicker nel file css. La dimensione del Datepicker può anche essere modificata in questo modo, basta regolare la dimensione del carattere.


4
Potresti dirmi, per favore, quali modifiche hai apportato?
eddy

1
@gfrizzle - sì, quella mia risposta era così sbagliata. Finalmente sono riuscito a raccoglierlo. Non ho idea di cosa stavo pensando allora: /
Kev

64
Non ho idea del motivo per cui questa sia la risposta accettata in quanto è quasi completamente inutile.
Software Engineer

10
La risposta data è completamente inutile in quanto datepicker modificherà dinamicamente il css di .ui-datepicker prima di far apparire il widget.
whaefelinger

4
Questa risposta non fornisce dettagli e non dovrebbe essere la risposta accettata.
Chapeljuice

120

Ecco cosa sto usando:

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

Potresti anche voler aggiungere un po 'di più al margine sinistro in modo che non sia proprio contro il campo di input.


2
Buon trucco. Il problema è che nei casi in cui il datepicker viene mostrato oltre i bordi dello schermo, _showDatepicker proverà a riposizionarlo, quindi, in alto e a sinistra saranno diversi e marginTop, marginLeft potrebbe richiedere una regolazione.
monzonj

1
Ho usato un approccio simile: ho preso la tua idea di usare beforeShow, ma la mia funzione beforeShow utilizza l'effetto di posizione di JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(dato che sto usando l' altFieldopzione datepicker per la visualizzazione)
Isaac Betesh

Questo può funzionare per impostare i margini, ma fallisce per gli attributi "left", "top", "z-index" e "position".
aaronbauman

A quanto ho capito, nemmeno questo funziona, perché jquery ripristina la posizione dopo che è stato chiamato beforeShow.
Software Engineer

La risposta data è sbagliata perché datepicker ripristinerà la posizione dopo che beforeShow () è tornato.
whaefelinger

40

Lo faccio direttamente nel CSS:

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

I miei campi di immissione della data sono tutti larghi 100 px. Ho anche aggiunto lo z-index in modo che il calendario appaia anche sopra i popup AJAX.

Non modifico il file CSS jquery-ui; Sovraccarico la classe nel mio file CSS principale, così posso cambiare il tema o aggiornare il widget senza dover reinserire le mie specifiche mod.


Stesso problema dell'altro trucco CSS: funziona solo se ora esattamente dove dovrebbe essere il datepicker in CSS. Non è possibile utilizzare questo metodo per posizionare dinamicamente il datepicker. Ho dovuto usare un hack, vincolante su inst.input.focus ()
aaronbauman

Ha funzionato per me usando Bootstrap :) ma ho impostato solo la proprietà z-index.
Francisco Goldenstein

Inutile per qualcosa di diverso da banali implementazioni in quanto non saprai dove si trova il campo di input sulla pagina.
Software Engineer

35

Ecco la mia variazione dell'allineamento del calendario Datepicker.

Penso che sia piuttosto carino, perché puoi controllare il posizionamento tramite jQuery UI Position util.

Una restrizione: jquery.ui.position.js richiesto.

Codice:

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

Grazie @kottenator, è davvero utile (specialmente con position.js)!
Sebastian

Questa risposta non mostra altro che i meriti di position.js.
whaefelinger

Funziona ancora nella v1.11.4 ma questo è davvero un trucco sporco, peccato che l'API jQuery non ci permetta di farlo in un afterShowmetodo.
Skoua

29

Ecco un'altra variazione che funziona bene per me, regola rect.top + 40, rect.left + 0 in base alle tue esigenze:

$(".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 funziona. Utilizzando "inst.dpDiv.css (" top "," 40px! Important ");" non funziona!
emeraldhieu

Lungi dall'essere perfetto per superare un problema programmatico introducendo un timeout.
whaefelinger

Grazie, questo ha funzionato per me, mi chiedo se ci sarà mai un evento afterShow, sarebbe fantastico !! Ma per ora questo mi aiuta ad
andare

16

Questo funziona per me:

 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

Per prima cosa penso che dovrebbe esserci un afterShowingmetodo nell'oggetto datepicker, dove potresti cambiare la posizione dopo che jquery ha fatto tutto il suo voodoo nel _showDatepickermetodo. Inoltre, preferedPositionsarebbe desiderabile anche un parametro chiamato , in modo da poterlo impostare e modificare jquery nel caso in cui la finestra di dialogo venga visualizzata al di fuori della finestra.

C'è un "trucco" per fare quest'ultima cosa. Se studi il _showDatepickermetodo, vedrai l'uso di una variabile privata $.datepikcer._pos. Quella variabile verrà impostata se nessuno l'ha impostata prima. Se modifichi quella variabile prima di mostrare la finestra di dialogo, Jquery la prenderà e proverà ad allocare la finestra di dialogo in quella posizione, e se il rendering esce dallo schermo, la regolerà per assicurarsi che sia visibile. Suona bene, eh?

Il problema è; _posè privato, ma se non ti dispiace. Puoi:

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

Ma fai attenzione agli aggiornamenti di Jquery-ui, perché un cambiamento nell'implementazione interna di _showDatepickerpotrebbe danneggiare il tuo codice.


1
Avrebbero dovuto aggiungerlo nell'interfaccia utente di jQuery come elemento configurabile.
Aleksej Komarov

3

Avevo bisogno di posizionare il datepicker in base a un div genitore all'interno del quale risiedeva il mio controllo di input senza bordi. Per farlo, ho utilizzato l'utility "position" inclusa nel core dell'interfaccia utente di jquery. L'ho fatto nell'evento beforeShow. Come altri hanno commentato sopra, non è possibile impostare la posizione direttamente in beforeShow, poiché il codice datepicker reimposterà la posizione dopo aver terminato la funzione beforeShow. Per aggirare questo problema, imposta semplicemente la posizione usando setInterval. Lo script corrente verrà completato, mostrando il datepicker, quindi il codice di riposizionamento verrà eseguito immediatamente dopo che il datepicker sarà visibile. Anche se non dovrebbe mai accadere, se il datepicker non è visibile dopo 0,5 secondi, il codice ha un fail-safe per rinunciare e cancellare l'intervallo.

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

Soluzione molto brutta. Il problema più grande sarebbe un notevole "salto" del widget datepicker subito dopo che è diventato visibile dove improvvisamente il tuo "trasferimento" entra in gioco. Da evitare a tutti i costi.
whaefelinger

2

bind focusin dopo aver usato datepicker cambia css del widget di datepicker auguro aiuto

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

2

l'ho risolto con il mio codice jquery personalizzato.

  1. ha assegnato al campo di immissione datepicker una classe " .datepicker2 "

  2. trova la sua posizione attuale dall'alto e

  3. posizionato la casella popup, il cui nome di classe è " .ui-datepicker "

ecco il mio codice.

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

qui "40" è il mio pixel atteso, puoi cambiare con il tuo.


1

risolto il problema della posizione dello spettacolo 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

Una funzione jquery molto semplice.

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

1

Ho passato una quantità ridicola di tempo cercando di capire questo problema per diverse pagine di un nuovo sito che sto sviluppando e nulla sembrava funzionare (comprese le varie soluzioni presentate sopra che ho implementato. Immagino che jQuery sia appena cambiato abbastanza da quando è stato suggerito che le soluzioni non funzionano più. Non lo so. Onestamente, non capisco perché non c'è qualcosa di semplice implementato nell'interfaccia utente di jQuery per configurarlo, come sembra un problema abbastanza grande con il calendario che si apre sempre in una posizione considerevolmente più in basso nella pagina dall'input a cui è allegato.

Comunque, volevo una soluzione finale che fosse abbastanza generica da poterla usare ovunque e avrebbe funzionato. Mi sembra di essere finalmente giunto a una conclusione che evita alcune delle risposte più complicate e specifiche del codice jQuery sopra:

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

Essenzialmente allego un nuovo tag di stile in testa prima di ogni evento "show" di datepicker (cancellando il precedente, se presente). Questo metodo di esecuzione aggira la maggior parte dei problemi che ho riscontrato durante lo sviluppo.

Testato su Chrome, Firefox, Safari e IE> 8 (poiché IE8 non funziona bene con jsFiddle e sto perdendo il mio gusto per

So che questo è un mix di contesti jQuery e javascript, ma a questo punto non voglio impegnarmi per convertirlo in jQuery. Sarebbe semplice, lo so. Ho così chiuso con questa cosa adesso. Spero che qualcun altro possa trarre vantaggio da questa soluzione.


1

Hanno cambiato il nome della classe in ui-datepicker-trigger

Quindi questo funziona jquery 1.11.x

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


1

Oppure puoi usare l'evento focus sull'oggetto dateSelect e posizionare l'API insieme. Puoi scambiare alto e basso e sinistra per destra o centro (o davvero qualsiasi cosa tu voglia dall'api di posizione). In questo modo non è necessario un intervallo o una soluzione follemente complessa e puoi configurare il layout in base alle tue esigenze a seconda di dove si trova l'input.

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

LA migliore / risposta più corretta !!
HirsuteJim

0

Vale anche la pena notare che se IE cade in modalità quirks, i componenti dell'interfaccia utente jQuery e altri elementi verranno posizionati in modo errato.

Per assicurarti di non cadere nella modalità quirks, assicurati di impostare correttamente il tuo doctype sull'ultimo HTML5.

<!DOCTYPE html>

Usare la transizione crea un pasticcio di cose. Si spera che questo possa far risparmiare tempo a qualcuno in futuro.


0

Ciò inserisce la funzionalità in un metodo denominato function, consentendo al codice di incapsularlo o di rendere il metodo un'estensione jquery. Appena usato sul mio codice, funziona perfettamente

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

All'interno di Jquery.UI, aggiorna semplicemente la funzione _checkOffset, in modo che viewHeight venga aggiunto a offset.top, prima che venga restituito offset.

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

Questa soluzione è essenzialmente corretta: inserisci la tua funzione _checkOffset () tramite jQuery.extend () e restituisci un oggetto arbitrario con proprietà numeriche "top" e "left", cioè jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); dove mytop e myleft è di tuo gradimento personale, ad esempio derivato da inst .
whaefelinger

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

perché il votato? questo non risolve il problema? codepen.io/coconewty/pen/rajbNj
James

votedown? Perché stavi solo leggendo il titolo della domanda e non hai fatto alcuno sforzo per approfondire il vero problema. Supponi semplicemente di avere due datepicker allegati ai campi di input con varie larghezze. In che modo la tua soluzione garantisce che il bordo sinistro di ogni widget Datepicker tocchi il bordo destro del campo di input? Dall'altro lato, dovresti ottenere almeno un punto per l'originalità delle tue risposte.
whaefelinger

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.