web-dev-qa-db-fra.com

Comment contrôler le positionnement de jQueryUI datepicker

Le datepicker dans jQueryUI s'affiche avec une position dynamique. Il rend en fonction de ses css s'il y a assez de place pour cela, mais s'il n'y a pas assez de fenêtre, il essaie de rendre à l'écran. J'en ai besoin pour rester en place et restituer au même endroit chaque fois, indépendamment de la position de l'écran ou d'autres circonstances. Comment cela peut-il être fait avec le datepicker de jQueryUI? D'autres implémentations de jQuery datepicker semblent avoir des façons de le faire, mais je ne vois pas de moyen de le faire pour la version d'interface utilisateur. 

La réponse ne semble pas simplement être une modification du fichier css:

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

... depuis la création du sélecteur de date, il crée dynamiquement le style de l'élément supérieur et inférieur. Je n'ai pas encore trouvé de solution. Une approche que j'ai vue consiste à donner quelque chose comme ceci dans l'option beforeShow:

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

Cela a un effet, mais les propriétés top et left sont toujours en cours de définition de manière dynamique après son exécution lorsque le paramètre datepicker est rendu. Il essaie toujours de rendre à l'écran. Comment puis-je le rendre toujours au même endroit? Ma prochaine étape est probablement d'aller dans les tripes du joueur de date et de commencer à tirer les choses. Des idées?

Notez que la réponse (pour la version de l'interface utilisateur) n'est pas dans:

33
Purrell

Afficher ceci dans l’espoir que cela aidera les autres. Au moins à partir de la version 1.8.1 de datepicker, l'utilisation de 'window.DP_jQuery.datepicker' ne fonctionne plus, car le pointeur (terme correct?) Est maintenant nommé avec un horodatage de sa création - il serait par exemple désormais 'window. DP_jQuery_1273700460448 '. Alors maintenant, plutôt que d'utiliser le pointeur sur l'objet datepicker, faites-le directement comme ceci:

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

Merci beaucoup pour la réponse ci-dessous pour m'avoir obtenu ce dont j'avais besoin.

64
JaredC

Edit: JaredC a donné une réponse mise à jour pour les versions ultérieures de jQuery ci-dessus. Changer de réponse acceptée à cela.

Très bien, il s’agit là d’affronter la fonctionnalité qu’il a de tenter de toujours restituer dans la fenêtre d’affichage car aucune option n’a été fournie pour activer/désactiver la fonctionnalité. Heureusement, il est découplé et isolé dans une fonction afin que nous puissions simplement le remplacer. Le code suivant désactive complètement cette fonctionnalité uniquement:

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

_checkOffset est appelé lors de son ouverture. Il effectue des calculs sur le décalage et renvoie un nouveau décalage s'il se trouvait autrement en dehors du port d'affichage. Ceci remplace le corps de la fonction pour simplement passer le décalage d'origine de part en part. Ensuite, vous pouvez utiliser le hack de réglage beforeShow et/ou la classe css .ui-datepicker pour le placer où vous voulez.

9
Purrell

bind focusin après avoir utilisé datepicker changer le css du widget datepicker

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

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

Dans votre fichier css, par exemple:

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

Vos paramètres importants, quels qu’ils soient, remplaceront les valeurs par défaut en ligne.

1
Joe Lalgee

Le problème que je rencontrais est que le sélecteur de date est mal positionné à l’intérieur d’éléments fixes, tels que fantaisie/lightboxes. Pour une raison quelconque, le sélecteur de date bascule en mode de positionnement "fixe" lorsque cela se produit, puis le calcul du décalage devient incorrect, lorsque le positionnement absolu aurait parfaitement fonctionné.

Cependant, nous pouvons obtenir la position fixe correcte avec ce hack:

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
mpen

plus tôt, j'ai essayé de donner top, laissé dans l'événement beforeShow de datepicker.js, qui est remplacé par la méthode _showDatePicker de jquery-ui-custom.js. Mais après la temporisation, la fenêtre fonctionne correctement. Ci-dessous le 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
Sudeep
$("first-selector").datepicker().bind('click',function () {
      $("#ui-datepicker-div").appendTo("other-selector");
});

<style>
#ui-datepicker-div {
        position: absolute !important;
        top: auto !important;
        left: auto !important;
        z-index: 99999999 !important;
}
</style>
1
Pardeep Goyal

C’est une question assez ancienne, mais j’ai récemment rencontré un problème similaire à celui de jQuery UI Datepicker. Nous utilisions déjà la solution postée par @JaredC ci-dessus (plus particulièrement cet extrait de code: $.extend($.datepicker,{_checkOffset:function(inst,offset,isFixed){return offset}});), mais cela ne fonctionnerait pas pour un modal avec une entrée dans laquelle nous devions afficher un menu déroulant.

Ce problème se produirait car lors du défilement de la page, le décalage de l'entrée dans les modifications modales par rapport au haut de la page défilée. Le comportement résultant signifierait que le sélecteur de date s'afficherait dans une position verticale différente en fonction de la distance à laquelle vous avez fait défiler la page (note: lorsque visible et que le défilement du sélecteur de date était déjà résolu). La solution à ce problème ("entrée de datepicker imbriquée dans un modal") consiste à calculer le positionnement vertical de l'entrée par rapport à l'écran de visualisation, puis à ajouter la hauteur de l'entrée (permettant à la propriété "top" css du datepicker être juste en dessous de celle de l'entrée). 

L'extrait suivant est en coffeescript. Au lieu de renvoyer le décalage normal selon la solution de @ JaredC, nous obtenons plutôt l'ID elementId de l'entrée de l'objet 'inst', puis nous accédons à l'objet via jquery afin de l'utiliser pour calculer la distance de l'entrée par rapport au haut de l'écran la fenêtre. 

# 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;
    }
});
1
Eric Walsh

La réponse acceptée fonctionne très bien dans l'ensemble.

Cependant, avec jQuery UI v1.11.4, je rencontrais un problème où le sélecteur de date se positionnerait loin de l'entrée dans une fenêtre modale (positionnement fixe) lorsque la fenêtre du navigateur aurait été déroulée. J'ai pu résoudre ce problème en modifiant la réponse acceptée comme suit:

const checkOffset = $.datepicker._checkOffset;

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

Voici comment cela a fonctionné pour moi:

$( "input[name='birthdate']" ).datepicker({
    beforeShow : function(input,inst){
    window.setTimeout(function () {
        $("#ui-datepicker-div").position({ my: "left top", at: "left bottom", of: input });
    }, 1);
    }
});

Pour le positionner lorsque l'écran est redimensionné:

$(window).resize(function(){ $("#ui-datepicker-div").position({ my: "left top", at: "left bottom", of: "input[name='birthdate']" }); });
0
obeliksz