Cómo cambiar la posición emergente del control jQuery DatePicker

109

¿Alguna idea de cómo hacer que DatePicker aparezca al final del cuadro de texto asociado en lugar de directamente debajo de él? Lo que suele suceder es que el cuadro de texto está hacia la parte inferior de la página y el DatePicker se desplaza hacia arriba para tener en cuenta y cubre totalmente el cuadro de texto. Si el usuario quiere escribir la fecha en lugar de elegirla, no puede. Prefiero que aparezca justo después del cuadro de texto para que no importe cómo se ajuste verticalmente.

¿Alguna idea de cómo controlar el posicionamiento? No vi ninguna configuración para el widget, y no he tenido suerte modificando la configuración de CSS, pero fácilmente podría faltar algo.

gfrizzle
fuente
1
+1 por no solo "abordar" la queja, que su solución no es la solución para D_N.
Leonidas

Respuestas:

20

La respuesta aceptada para esta pregunta en realidad no es para jQuery UI Datepicker. Para cambiar la posición de jQuery UI Datepicker simplemente modifique .ui-datepicker en el archivo css. El tamaño del selector de fecha también se puede cambiar de esta manera, simplemente ajuste el tamaño de la fuente.

jonmc12
fuente
4
¿Podría decirme qué cambios realizó?
Eddy
1
@gfrizzle - sí, esa respuesta mía fue tan incorrecta. Finalmente llegué a desecharlo. No tengo idea de lo que estaba pensando en ese entonces: /
Kev
64
No tengo idea de por qué esta es la respuesta aceptada, ya que es casi completamente inútil.
Ingeniero de software
10
La respuesta dada es completamente inútil ya que datepicker modificará dinámicamente el CSS de .ui-datepicker antes de que aparezca el widget.
whaefelinger
4
Esta respuesta no proporciona ningún detalle y no debería ser la respuesta aceptada.
chapeljuice
120

Esto es lo que estoy usando:

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

Es posible que también desee agregar un poco más al margen izquierdo para que no esté justo contra el campo de entrada.


fuente
2
Buen truco. El problema es que en los casos en que el selector de fecha se muestra más allá de los bordes de la pantalla, _showDatepicker intentará reubicarlo, por lo tanto, la parte superior e izquierda serán diferentes y marginTop, marginLeft pueden necesitar ajustes.
Monzonj
1
Usé un enfoque similar: tomé su idea de usar beforeShow, pero mi función beforeShow usa el efecto de posición de JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(ya que estoy usando la altFieldopción de datepicker para mostrar)
Isaac Betesh
Esto puede funcionar para establecer márgenes, pero falla para los atributos "left", "top", "z-index" y "position".
Aaronbauman
Según tengo entendido, esto tampoco funciona, porque jquery restablece la posición después de que se llama a beforeShow.
Software Engineer
La respuesta dada es incorrecta porque datepicker restablecerá la posición después de que beforeShow () regresara.
whaefelinger
40

Lo hago directamente en el CSS:

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

Mis campos de entrada de fecha tienen 100 píxeles de ancho. También agregué el índice z para que el calendario también aparezca sobre las ventanas emergentes de AJAX.

No modifico el archivo CSS jquery-ui; Sobrecargo la clase en mi archivo CSS principal, por lo que puedo cambiar el tema o actualizar el widget sin tener que volver a ingresar mis mods específicos.

Christian Lescuyer
fuente
El mismo problema que el otro truco css: solo funciona si ahora exactamente dónde debería estar el selector de fechas en CSS. No puede utilizar este método para colocar dinámicamente el selector de fechas. Tuve que usar un truco, vinculante en inst.input.focus ()
aaronbauman
Me funcionó usando Bootstrap :) pero solo configuré la propiedad z-index.
Francisco Goldenstein
Inútil para cualquier otra cosa que no sean implementaciones triviales, ya que no sabrá dónde está el campo de entrada en la página.
Software Engineer
35

Aquí está mi variación de la alineación del calendario Datepicker.

Creo que es bastante bueno, porque puedes controlar el posicionamiento a través de jQuery UI Position util.

Una restricción: se requiere jquery.ui.position.js.

Código:

$('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);
    }
})
Rost
fuente
Gracias @kottenator, ¡esto es realmente útil (especialmente con position.js)!
Sebastián
Esta respuesta muestra nada más que los méritos de position.js.
whaefelinger
Esto todavía funciona en v1.11.4 pero de hecho es un truco sucio, lástima que la API de jQuery no nos permite hacer esto en un afterShowmétodo.
Skoua
29

Aquí hay otra variación que me funciona bien, ajuste el rect.top + 40, rect.left + 0 para satisfacer sus necesidades:

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

Patricio
fuente
Vaya, funciona. Usando "inst.dpDiv.css (" top "," 40px! Important ");" ¡No funciona!
emeraldhieu
Lejos de ser perfecto para superar un problema programático mediante la introducción de un tiempo de espera.
whaefelinger
Gracias, esto funcionó para mí, me pregunto si alguna vez habrá un evento afterShow, ¡sería genial! Pero por ahora esto me ayuda a seguir adelante independientemente: D
Rob Branaghan
16

Esto funciona para mi:

 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);
David Laberge
fuente
6

Primero, creo que debería haber un afterShowingmétodo en el objeto datepicker, donde podría cambiar la posición después de que jquery haya hecho todo su vudú en el _showDatepickermétodo. Además, un parámetro llamado preferedPositiontambién sería deseable, por lo que podría configurarlo y jquery modificarlo en caso de que el diálogo se represente fuera de la ventana gráfica.

Hay un "truco" para hacer esto último. Si estudia el _showDatepickermétodo, verá el uso de una variable privada $.datepikcer._pos. Esa variable se configurará si nadie la ha configurado antes. Si modifica esa variable antes de mostrar el diálogo, Jquery la tomará e intentará ubicar el diálogo en esa posición, y si se renderiza fuera de la pantalla, lo ajustará para asegurarse de que esté visible. Suena bien, ¿eh?

El problema es; _poses privado, pero si no te importa. Usted puede:

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

Pero tenga cuidado con las actualizaciones de Jquery-ui, porque un cambio en la implementación interna de la _showDatepickerpuede romper su código.

monzonj
fuente
1
Deberían haber estado agregando esto en jQuery UI como elemento configurable.
Aleksej Komarov
3

Necesitaba colocar el selector de fechas de acuerdo con un div principal dentro del cual residía mi control de entrada sin bordes. Para hacerlo, utilicé la utilidad de "posición" incluida en el núcleo de jquery UI. Hice esto en el evento beforeShow. Como otros comentaron anteriormente, no puede establecer la posición directamente en beforeShow, ya que el código datepicker restablecerá la ubicación después de finalizar la función beforeShow. Para evitar eso, simplemente establezca la posición usando setInterval. La secuencia de comandos actual se completará, mostrando el selector de fecha, y luego el código de reposicionamiento se ejecutará inmediatamente después de que el selector de fecha sea visible. Aunque nunca debería suceder, si el selector de fecha no es visible después de .5 segundos, el código tiene una seguridad para darse por vencido y borrar el intervalo.

        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);
        }
Brett Birschbach
fuente
Solución muy fea. El mayor problema sería un notable "salto" del widget de selector de fechas justo después de que se hizo visible, donde de repente se activa su "reubicación". Debe evitarse a toda costa.
whaefelinger
2

enlazar focusin después de usar datepicker cambiar css del widget de datepicker desea ayuda

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

Lo arreglé con mi código jquery personalizado.

  1. le di a mi campo de entrada datepicker una clase " .datepicker2 "

  2. encontrar su posición actual desde arriba y

  3. colocó el cuadro emergente, cuyo nombre de clase es " .ui-datepicker "

aquí está mi código.

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

aquí "40" es mi píxel esperado, puede cambiar con el suyo.

sh6210
fuente
1

arreglar mostrar posición problema 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();
        }
    }
zersina
fuente
1

Una función jquery muy simple.

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

Pasé una cantidad ridícula de tiempo tratando de resolver este problema para varias páginas de un nuevo sitio que estoy desarrollando y nada parecía funcionar (incluida cualquiera de las diversas soluciones presentadas anteriormente que implementé. Supongo que jQuery acaba de cambiar las cosas han subido lo suficiente ya que se sugirió que las soluciones ya no funcionan. No lo sé. Honestamente, no entiendo por qué no hay algo simple implementado en la interfaz de usuario de jQuery para configurar esto, como parece ser un problema bastante grande con el calendario siempre apareciendo en alguna posición considerablemente más abajo en la página de la entrada a la que está adjunto.

De todos modos, quería una solución final que fuera lo suficientemente genérica como para poder usarla en cualquier lugar y funcionaría. Parece que finalmente he llegado a una conclusión que evita algunas de las respuestas más complicadas y específicas del código jQuery anteriores:

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

Esencialmente adjunto una nueva etiqueta de estilo al encabezado antes de cada evento "show" del selector de fechas (eliminando la anterior, si está presente). Este método de hacer las cosas soluciona la gran mayoría de los problemas que encontré durante el desarrollo.

Probado en Chrome, Firefox, Safari e IE> 8 (ya que IE8 no funciona bien con jsFiddle y estoy perdiendo el gusto por preocuparme

Sé que esta es una mezcla de contextos jQuery y javascript, pero en este punto simplemente no quiero esforzarme en convertirlo a jQuery. Sería simple, lo sé. Estoy tan harto de esto ahora mismo. Espero que alguien más pueda beneficiarse de esta solución.

Programador Dan
fuente
1

Cambiaron el nombre de la clase a ui-datepicker-trigger

Entonces esto funciona en jquery 1.11.x

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

O puede usar el evento de enfoque en su objeto dateSelect y posicionar api juntos. Puede cambiar la parte superior e inferior e izquierda por la derecha o el centro (o realmente cualquier cosa que desee de la API de posición). De esta manera, no necesita un intervalo ni ninguna solución increíblemente compleja y puede configurar el diseño para que se adapte a sus necesidades dependiendo de dónde esté la entrada.

dateSelect.focus(function () {
    $("#ui-datepicker-div").position({
        my: "left top",
        at: "left bottom",
        of: $(this)
    });
});
Taugenichts
fuente
¡¡La mejor / más correcta respuesta !!
HirsuteJim
0

También vale la pena señalar que si IE cae en modo peculiar, los componentes de la interfaz de usuario de jQuery y otros elementos se colocarán incorrectamente.

Para asegurarse de no caer en el modo peculiar, asegúrese de configurar su tipo de documento correctamente en el último HTML5.

<!DOCTYPE html>

El uso de Transicional hace que las cosas sean un desastre. Con suerte, esto le ahorrará a alguien algo de tiempo en el futuro.

Halfstop
fuente
0

Esto coloca la funcionalidad en un método llamado función, lo que permite que su código lo encapsule o que el método se convierta en una extensión jquery. Solo usado en mi código, funciona perfectamente

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);
}
Brett Weber
fuente
0

Dentro de Jquery.UI, simplemente actualice la función _checkOffset, para que viewHeight se agregue a offset.top, antes de que se devuelva el 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;
    },
David Moore
fuente
Esta solución es esencialmente correcta: inyecte su propia función _checkOffset () a través de jQuery.extend () y devuelva un objeto arbitrario con propiedades numéricas "top" e "left", es decir, jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); donde mytop y myleft son de su agrado personal, por ejemplo derivado de inst .
whaefelinger
0
.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}
James
fuente
¿Por qué el voto negativo? ¿No resuelve esto el problema? codepen.io/coconewty/pen/rajbNj
James
¿rechazar? Porque solo estaba leyendo el título de la pregunta y no hizo ningún esfuerzo para profundizar en el problema real. Simplemente asuma que tiene dos selectores de fecha adjuntos a los campos de entrada con varios anchos. ¿Cómo garantiza su solución que el borde izquierdo de cada widget de selector de fechas toque el borde derecho del campo de entrada? Por otro lado, debes obtener al menos un punto por la originalidad de tus respuestas.
whaefelinger
0
$('.PDatePicker').MdPersianDateTimePicker({
                Placement: 'top',          
            });
hamed hossani
fuente