Comment changer la position du pop-up du contrôle jQuery DatePicker

109

Une idée comment faire apparaître le DatePicker à la fin de la zone de texte associée au lieu de directement en dessous? Ce qui a tendance à se produire, c'est que la zone de texte est vers le bas de la page et le DatePicker se décale pour en tenir compte et recouvre totalement la zone de texte. Si l'utilisateur souhaite saisir la date au lieu de la sélectionner, il ne le peut pas. Je préfère le faire apparaître juste après la zone de texte pour que la façon dont elle s'ajuste verticalement importe peu.

Une idée comment contrôler le positionnement? Je n'ai vu aucun paramètre pour le widget, et je n'ai pas eu de chance de peaufiner les paramètres CSS, mais je pourrais facilement manquer quelque chose.

gfrizzle
la source
1
+1 pour non seulement "adresser" la plainte, que votre solution n'est pas la solution pour D_N.
Leonidas

Réponses:

20

La réponse acceptée pour cette question n'est en fait pas pour le jQuery UI Datepicker. Pour changer la position de l'interface utilisateur jQuery Datepicker, modifiez simplement .ui-datepicker dans le fichier css. La taille du Datepicker peut également être modifiée de cette manière, il suffit d'ajuster la taille de la police.

jonmc12
la source
4
Pourriez-vous me dire quelles modifications vous avez apportées?
eddy
1
@gfrizzle - oui, ma réponse était tellement fausse. J'ai finalement réussi à le mettre dans un bac. Aucune idée de ce à quoi je pensais à l'époque: /
Kev
64
Je n'ai aucune idée de pourquoi c'est la réponse acceptée car elle est presque complètement inutile.
Ingénieur logiciel
10
La réponse donnée est complètement inutile car datepicker modifie dynamiquement le css de .ui-datepicker avant de faire apparaître le widget.
whaefelinger
4
Cette réponse ne donne aucun détail et ne devrait pas être la réponse acceptée.
chapeljuice
120

Voici ce que j'utilise:

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

Vous voudrez peut-être également en ajouter un peu plus à la marge de gauche pour ne pas être en face du champ de saisie.


la source
2
Bon truc. Le problème est que dans les cas où le sélecteur de date est affiché au-delà des bordures de l'écran, le _showDatepicker essaiera de le déplacer, par conséquent, le haut et la gauche seront différents et marginTop, marginLeft pourrait nécessiter un réglage.
monzonj
1
J'ai utilisé une approche similaire - j'ai repris votre idée d'utiliser beforeShow, mais ma fonction beforeShow utilise l'effet de position de JQueryUI: $(this).position(my:'left top', at:'left bottom', of:'#altField')(puisque j'utilise l' altFieldoption datepicker pour l'affichage)
Isaac Betesh
Cela peut fonctionner pour définir des marges, mais échoue pour les attributs "left", "top", "z-index" et "position".
aaronbauman
Si je comprends bien, cela ne fonctionne pas non plus, car jquery réinitialise la position après l'appel de beforeShow.
Ingénieur logiciel
La réponse donnée est fausse car datepicker réinitialisera la position après le retour de beforeShow ().
whaefelinger le
40

Je le fais directement dans le CSS:

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

Mes champs de saisie de date ont tous une largeur de 100 px. J'ai également ajouté le z-index pour que le calendrier apparaisse également au-dessus des popups AJAX.

Je ne modifie pas le fichier CSS jquery-ui; Je surcharge la classe dans mon fichier CSS principal, donc je peux changer le thème ou mettre à jour le widget sans avoir à ressaisir mes mods spécifiques.

Christian Lescuyer
la source
Même problème que l'autre astuce css: ne fonctionne que si vous maintenant exactement où le sélecteur de date devrait être dans CSS. Vous ne pouvez pas utiliser cette méthode pour placer dynamiquement le sélecteur de date. J'ai dû utiliser un hack, lié à inst.input.focus ()
aaronbauman
A travaillé pour moi en utilisant Bootstrap :) mais je n'ai défini que la propriété z-index.
Francisco Goldenstein
Inutile pour autre chose que des implémentations triviales car vous ne saurez pas où se trouve le champ de saisie sur la page.
Ingénieur logiciel
35

Voici ma variante de l'alignement du calendrier Datepicker.

Je pense que c'est plutôt sympa, car vous pouvez contrôler le positionnement via jQuery UI Position util.

Une restriction: jquery.ui.position.js requis.

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);
    }
})
Rost
la source
Merci @kottenator, c'est vraiment utile (surtout avec position.js)!
Sebastian
Cette réponse ne montre rien de plus que les mérites de position.js.
whaefelinger
Cela fonctionne toujours en v1.11.4 mais c'est en effet un sale hack, dommage que l'API jQuery ne nous laisse pas faire cela dans une afterShowméthode.
Skoua
29

Voici une autre variante qui fonctionne bien pour moi, ajustez le rect.top + 40, rect.left + 0 en fonction de vos besoins:

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

Patrick
la source
Wow ça marche. Utilisation de "inst.dpDiv.css (" top "," 40px! Important ");" ne marche pas!
emeraldhieu
Loin d'être parfait pour surmonter un problème de programmation en introduisant un timeout.
whaefelinger le
Merci, cela a fonctionné pour moi, je me demande s'il y aura jamais un événement afterShow, ce serait génial !! Mais pour l'instant, cela m'aide à continuer malgré tout: D
Rob Branaghan
16

Cela fonctionne pour moi:

 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
la source
6

Tout d'abord, je pense qu'il devrait y avoir une afterShowingméthode dans l'objet datepicker, où vous pouvez changer la position après que jquery a fait tout son vaudou dans la _showDatepickerméthode. En outre, un paramètre appelé preferedPositionserait également souhaitable, vous pouvez donc le définir et le modifier au cas où la boîte de dialogue serait rendue en dehors de la fenêtre.

Il y a un "truc" pour faire cette dernière chose. Si vous étudiez la _showDatepickerméthode, vous verrez l'utilisation d'une variable privée $.datepikcer._pos. Cette variable sera configurée si personne ne l'a déjà configurée. Si vous modifiez cette variable avant d'afficher la boîte de dialogue, Jquery la prendra et essaiera d'allouer la boîte de dialogue dans cette position, et si elle est restituée hors de l'écran, elle l'ajustera pour s'assurer qu'elle est visible. Ça sonne bien, hein?

Le problème est; _posest privé, mais si cela ne vous dérange pas. Vous pouvez:

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

Mais faites attention aux mises à jour de Jquery-ui, car un changement dans l'implémentation interne du _showDatepickerpeut casser votre code.

monzonj
la source
1
Ils auraient dû l'ajouter dans l'interface utilisateur jQuery en tant qu'élément configurable.
Aleksej Komarov
3

J'avais besoin de positionner le sélecteur de date en fonction d'un div parent dans lequel résidait mon contrôle d'entrée sans bordure. Pour ce faire, j'ai utilisé l'utilitaire "position" inclus dans jquery UI core. Je l'ai fait lors de l'événement beforeShow. Comme d'autres l'ont commenté ci-dessus, vous ne pouvez pas définir la position directement dans beforeShow, car le code de sélection de date réinitialisera l'emplacement après avoir terminé la fonction beforeShow. Pour contourner cela, définissez simplement la position à l'aide de setInterval. Le script actuel se terminera, montrant le sélecteur de date, puis le code de repositionnement s'exécutera immédiatement après que le sélecteur de date soit visible. Bien que cela ne devrait jamais arriver, si le sélecteur de date n'est pas visible après 0,5 seconde, le code a une sécurité intégrée pour abandonner et effacer l'intervalle.

        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
la source
Solution très moche. Le plus gros problème serait un "saut" perceptible du widget de sélection de date juste après qu'il soit devenu visible où soudainement votre "relocalisation" entre en jeu. A éviter à tout prix.
whaefelinger
2

lier le focusin après avoir utilisé datepicker changer le css du widget datepicker souhaiter de l'aide

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

je l'ai corrigé avec mon code jquery personnalisé.

  1. a donné à mon champ de saisie datepicker une classe " .datepicker2 "

  2. trouver sa position actuelle du haut et

  3. positionné la boîte de dialogue , dont le nom de classe est " .ui-datepicker "

voici mon code.

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

ici "40" est mon pixel attendu, vous pouvez changer avec le vôtre.

sh6210
la source
1

correction du problème de position d'affichage 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
la source
1

Une fonction jquery très simple.

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

J'ai passé un temps ridicule à essayer de résoudre ce problème pour plusieurs pages d'un nouveau site que je développe et rien ne semblait fonctionner (y compris les différentes solutions présentées ci-dessus que j'ai implémentées. Je suppose que jQuery vient de changer les choses se sont suffisamment améliorées depuis qu'on leur a suggéré que les solutions ne fonctionnent plus. Je ne sais pas. Honnêtement, je ne comprends pas pourquoi il n'y a pas quelque chose de simple implémenté dans l'interface utilisateur jQuery pour configurer cela, comme cela semble être un problème assez important avec le calendrier qui apparaît toujours à une certaine position considérablement en bas de la page à partir de l'entrée à laquelle il est attaché.

Quoi qu'il en soit, je voulais une solution finale suffisamment générique pour pouvoir l'utiliser n'importe où et cela fonctionnerait. Il me semble être enfin arrivé à une conclusion qui évite certaines des réponses les plus compliquées et spécifiques au code jQuery ci-dessus:

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

Essentiellement, j'attache une nouvelle balise de style à la tête avant chaque événement "show" de datepicker (en supprimant le précédent, s'il est présent). Cette méthode permet de contourner une grande majorité des problèmes que j'ai rencontrés pendant le développement.

Testé sur Chrome, Firefox, Safari et IE> 8 (car IE8 ne fonctionne pas bien avec jsFiddle et je perds le goût de me soucier de

Je sais qu'il s'agit d'un mélange de contextes jQuery et javascript, mais à ce stade, je ne veux tout simplement pas faire l'effort de le convertir en jQuery. Ce serait simple, je sais. J'en ai tellement fini avec cette chose en ce moment. J'espère que quelqu'un d'autre pourra bénéficier de cette solution.

Programmeur Dan
la source
1

Ils ont changé le nom de la classe en ui-datepicker-trigger

Donc cela fonctionne dans jquery 1.11.x

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

Ou vous pouvez utiliser l'événement focus sur votre objet dateSelect et positionner l'API ensemble. Vous pouvez permuter le haut et le bas et la gauche pour la droite ou le centre (ou vraiment tout ce que vous voulez de l'api de position). De cette façon, vous n'avez pas besoin d'un intervalle ou d'une solution incroyablement complexe et vous pouvez configurer la mise en page en fonction de vos besoins en fonction de l'emplacement de l'entrée.

dateSelect.focus(function () {
    $("#ui-datepicker-div").position({
        my: "left top",
        at: "left bottom",
        of: $(this)
    });
});
Taugenichts
la source
LA meilleure / la plus correcte réponse !!
HirsuteJim
0

Il est également intéressant de noter que si IE tombe en mode bizarreries, vos composants d'interface utilisateur jQuery et d'autres éléments seront mal positionnés.

Pour vous assurer de ne pas tomber en mode bizarreries, assurez-vous de définir correctement votre doctype sur le dernier HTML5.

<!DOCTYPE html>

L'utilisation de la transition fait du désordre. Espérons que cela permettra à quelqu'un de gagner du temps dans le futur.

Demi-arrêt
la source
0

Cela place la fonctionnalité dans une méthode nommée function, permettant à votre code de l'encapsuler ou de faire de la méthode une extension jquery. Juste utilisé sur mon code, fonctionne parfaitement

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
la source
0

Dans Jquery.UI, mettez simplement à jour la fonction _checkOffset, afin que viewHeight soit ajouté à offset.top, avant que l'offset ne soit renvoyé.

_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
la source
Cette solution est essentiellement correcte: Injectez votre propre fonction _checkOffset () via jQuery.extend () et retournez un objet arbitraire ayant des propriétés numériques "top" et "left", c'est à dire jQuery.extend (jQuery.datepicker, {_checkOffset: function (inst , offset, isFixed) {return {top: mytop , left: myleft };}}); où mytop et myleft sont à votre goût personnel, par exemple dérivé de inst .
whaefelinger le
0
.ui-datepicker {-ms-transform: translate(100px,100px); -webkit-transform: translate(100px,100px); transform: translate(100px,100px);}
James
la source
pourquoi la votation? cela ne résout pas le problème? codepen.io/coconewty/pen/rajbNj
James
voter contre? Parce que vous ne lisiez que le titre de la question et que vous n'avez fait aucun effort pour creuser le vrai problème. Supposons simplement que vous ayez deux sélecteurs de date attachés aux champs de saisie de différentes largeurs. Comment votre solution garantit-elle que le bord gauche de chaque widget datepicker touche le bord droit du champ de saisie? De l'autre côté, vous devriez obtenir au moins un point pour l'originalité de vos réponses.
whaefelinger le
0
$('.PDatePicker').MdPersianDateTimePicker({
                Placement: 'top',          
            });
jambon hossani
la source