web-dev-qa-db-fra.com

Empêcher la boîte de dialogue jQuery UI de définir le focus sur le premier champ de texte

J'ai configuré une boîte de dialogue modale jQuery UI à afficher lorsqu'un utilisateur clique sur un lien. Il y a deux zones de texte (je montre seulement le code pour 1 par souci de brièveté) dans cette balise div et elle est modifiée pour être une zone de texte jQuery UI DatePicker qui réagit au focus.

Le problème est que la boîte de dialogue de l'interface utilisateur jQuery ("ouvrir") déclenche en quelque sorte que le premier champ de texte soit activé, ce qui déclenche l'ouverture immédiate du calendrier datepicker.

Je cherche donc un moyen d'éviter que la mise au point ne se produise automatiquement.

<div><a id="lnkAddReservation" href="#">Add reservation</a></div>

<div id="divNewReservation" style="display:none" title="Add reservation">
    <table>
        <tr>
            <th><asp:Label AssociatedControlID="txtStartDate" runat="server" Text="Start date" /></th>
            <td>
                <asp:TextBox ID="txtStartDate" runat="server" CssClass="datepicker" />
            </td>
        </tr>
    </table>

    <div>
        <asp:Button ID="btnAddReservation" runat="server" OnClick="btnAddReservation_Click" Text="Add reservation" />
    </div>
</div>

<script type="text/javascript">
    $(document).ready(function() {
        var dlg = $('#divNewReservation');
        $('.datepicker').datepicker({ duration: '' });
        dlg.dialog({ autoOpen:false, modal: true, width:400 });
        $('#lnkAddReservation').click(function() { dlg.dialog('open'); return false; });
        dlg.parent().appendTo(jQuery("form:first"));
    });
</script>
152
slolife

Historique des modifications de jQuery 1.10. répertorie ticket 4731 comme étant en cours de correction.

On dirait que focusSelector n'a pas été implémenté, mais une recherche en cascade de divers éléments a été utilisée à la place. Du billet:

Étendre l'autofocus, en commençant par [autofocus], puis par: contenu tabable, puis bouton, puis bouton, puis boîte de dialogue

Donc, marquez un élément avec l'attribut autofocus et c'est l'élément qui devrait avoir le focus:

<input autofocus>

Dans la documentation , la logique du focus est expliquée (juste sous la table des matières, sous le titre 'Focus'):

Lors de l'ouverture d'une boîte de dialogue, le focus est automatiquement placé sur le premier élément correspondant aux éléments suivants:

  1. Le premier élément de la boîte de dialogue avec l'attribut autofocus
  2. La première :tabbable élément dans le contenu du dialogue
  3. La première :tabbable élément dans la fenêtre de la boîte de dialogue
  4. Le bouton de fermeture du dialogue
  5. Le dialogue lui-même
76
slolife

Ajoutez une étendue cachée au-dessus, utilisez ui-helper-hidden-accessible pour le masquer par positionnement absolu. Je sais que vous avez cette classe parce que vous utilisez la boîte de dialogue de jquery-ui et qu'elle se trouve dans jquery-ui.

<span class="ui-helper-hidden-accessible"><input type="text"/></span>
74

Dans jQuery UI> = 1.10.2, vous pouvez remplacer le _focusTabbable méthode du prototype par une fonction placebo:

$.ui.dialog.prototype._focusTabbable = $.noop;

Fiddle

Cela affectera tous les dialogs de la page sans nécessiter leur modification manuelle.

La fonction d'origine ne fait que placer le focus sur le premier élément avec autofocus attribut/tabbable élément/ou revenir au dialogue lui-même. Comme son utilisation consiste simplement à mettre le focus sur un élément, il ne devrait pas y avoir de problème à le remplacer par un noop.

60
Fabrício Matté

J'ai trouvé le code suivant la fonction de dialogue jQuery UI pour open.

c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();

Vous pouvez contourner le comportement de jQuery ou modifier le comportement.

tabindex -1 fonctionne comme une solution de contournement.

28
user53067

À partir de jQuery UI 1.10.0, vous pouvez choisir sur quel élément d'entrée vous concentrer en utilisant l'attribut HTML5 autofocus .

Tout ce que vous avez à faire est de créer un élément factice comme première entrée dans la boîte de dialogue. Il va absorber l'attention pour vous.

<input type="hidden" autofocus="autofocus" />

Cela a été testé dans Chrome, Firefox et Internet Explorer (toutes les dernières versions) le 7 février 2013.

http://jqueryui.com/upgrade-guide/1.10/#added-ability-to-specify-which-element-to-focus-on-open

26
silkfire

Je viens de comprendre cela en jouant.

J'ai trouvé avec ces solutions pour supprimer le focus, causé la ESC pour arrêter de travailler (fermer la boîte de dialogue) lors de la première utilisation de la boîte de dialogue.

Si la boîte de dialogue s'ouvre et que vous appuyez immédiatement sur ESC, la boîte de dialogue ne se fermera pas (si cette option est activée), car l’accent est mis sur un champ caché ou quelque chose d’autre, et les événements de frappe de touche ne se produisent pas.

La façon dont j'ai résolu le problème consistait à ajouter ceci à l'événement open pour supprimer le focus du premier champ:

$('#myDialog').dialog({
    open: function(event,ui) {
        $(this).parent().focus();
    }
});

Ceci active la boîte de dialogue, qui n'est pas visible, puis le ESC travaux clés.

13
Rob Donovan

Définissez le tabindex de l'entrée sur -1, puis définissez dialog.open pour restaurer tabindex si vous en avez besoin ultérieurement:

$(function() {
    $( "#dialog-message" ).dialog({
        modal: true,
        width: 500,
        autoOpen: false,
        resizable: false,
        open: function()
        {
            $( "#datepicker1" ).attr("tabindex","1");
            $( "#datepicker2" ).attr("tabindex","2");
        }
    });
});
10
redsquare

Ma solution de contournement:

open: function(){
  jQuery('input:first').blur();
  jQuery('#ui-datepicker-div').hide();
},  
10
Thomas

J'avais un contenu qui était plus long que le dialogue. À l'ouverture, la boîte de dialogue défilait jusqu'au premier: tabbable qui se trouvait en bas. Voici ma solution.

$("#myDialog").dialog({
   ...
   open: function(event, ui) { $(this).scrollTop(0); }
});
7
thetoolman

Contournement simple:

Il suffit de créer un élément invisible avec tabindex = 1 ... Cela ne va pas focaliser le sélecteur de date ...

par exemple.:

<a href="" tabindex="1"></a>
...
Here comes the input element
7
Andy

Voici la solution que j'ai mise en œuvre après avoir lu ticket jQuery UI # 4731 , posté à l'origine par slolife en réponse à une autre réponse. (Le billet a également été créé par lui.)

Premièrement, quelle que soit la méthode que vous appliquez pour appliquer la saisie semi-automatique à la page, ajoutez la ligne de code suivante:

$.ui.dialog.prototype._focusTabbable = function(){};

Cela désactive le comportement "auto-focus" de jQuery. Pour que votre site continue à être largement accessible, encapsulez vos méthodes de création de boîte de dialogue afin d'ajouter du code supplémentaire, puis ajoutez un appel pour mettre en évidence le premier élément d'entrée:

function openDialog(context) {

    // Open your dialog here

    // Usability for screen readers.  Focus on an element so that screen readers report it.
    $("input:first", $(context)).focus();

}

Pour améliorer l’accessibilité lorsque les options de saisie semi-automatique sont sélectionnées à l’aide du clavier, nous remplaçons le rappel "select" de saisie sélective de jQuery UI et ajoutons du code supplémentaire pour garantir que textElement ne perdra pas le focus dans IE 8 après avoir effectué une sélection). .

Voici le code que nous utilisons pour appliquer des compléments automatiques aux éléments:

$.fn.applyAutocomplete = function () {

    // Prevents jQuery dialog from auto-focusing on the first tabbable element.
    // Make sure to wrap your dialog opens and focus on the first input element
    // for screen readers.
    $.ui.dialog.prototype._focusTabbable = function () { };

    $(".autocomplete", this)
        .each(function (index) {

            var textElement = this;

            var onSelect = $(this).autocomplete("option", "select");
            $(this).autocomplete("option", {
                select: function (event, ui) {
                    // Call the original functionality first
                    onSelect(event, ui);

                    // We replace a lot of content via AJAX in our project.
                    // This ensures proper copying of values if the original element which jQuery UI pointed to
                    // is replaced.
                    var $hiddenValueElement = $("#" + $(textElement).attr('data-jqui-acomp-hiddenvalue'));
                    if ($hiddenValueElement.attr("value") != ui.item.value) {
                        $hiddenValueElement.attr("value", ui.item.value);
                    }

                    // Replace text element value with that indicated by "display" if any
                    if (ui.item.display)
                        textElement.value = ui.item.display;

                    // For usability purposes.  When using the keyboard to select from an autocomplete, this returns focus to the textElement.
                    $(textElement).focus();

                    if (ui.item.display)
                        return false;

                }
            });
        })
        // Set/clear data flag that can be checked, if necessary, to determine whether list is currently dropped down
        .on("autocompleteopen", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = true;
        })
        .on("autocompleteclose", function (event, ui) {
            $(event.target).data().autocompleteIsDroppedDown = false;
        });

    return this;
}
3

Vous pouvez fournir cette option pour concentrer le bouton de fermeture à la place.

.dialog({
      open: function () {
              $(".ui-dialog-titlebar-close").focus();
            }
   });
2
Jay Dubal

Si vous n'avez qu'un seul champ sous la forme de boîte de dialogue Jquery et que c'est celui qui nécessite Datepicker, vous pouvez également définir le focus sur la boîte de dialogue bouton Fermer (croix) dans la barre de titre de la boîte de dialogue:

$('.ui-dialog-titlebar-close').focus();

Appeler ce dialogue APRES a été initialisé, par exemple:

$('#yourDialogId').dialog();
$('.ui-dialog-titlebar-close').focus();

Parce que le bouton de fermeture est rendu après l'appel de la .dialog().

1
mik-t

C'est bien que personne n'ait trouvé la solution pour l'instant, mais il semblerait que j'ai quelque chose pour vous. La mauvaise nouvelle est que la boîte de dialogue s'active dans tous les cas, même si aucune entrée ni aucun lien ne se trouvent à l'intérieur. J'utilise le dialogue comme une info-bulle et j'ai certainement besoin de rester concentré dans l'élément d'origine. Voici ma solution:

utiliser l'option [autoOpen: false]

$toolTip.dialog("widget").css("visibility", "hidden"); 
$toolTip.dialog("open");
$toolTip.dialog("widget").css("visibility", "visible");

Bien que la boîte de dialogue soit invisible, la mise au point n'est définie nulle part et reste à la place d'origine. Cela fonctionne pour les info-bulles avec seulement un texte brut, mais n’a pas été testé pour des dialogues plus fonctionnels où il peut être important d’avoir un dialogue visible au moment de l’ouverture. Cela fonctionnera probablement bien dans tous les cas.

Je comprends que le message original visait simplement à éviter de se focaliser sur le premier élément, mais vous pouvez facilement décider où le focus doit être placé après l’ouverture de la boîte de dialogue (après mon code).

Testé dans IE, FF et Chrome.

J'espère que cela aidera quelqu'un.

1
Roc

Si vous utilisez des boutons de dialogue, définissez simplement l'attribut autofocus sur l'un des boutons:

$('#dialog').dialog({
  buttons: [
    {
      text: 'OK',
      autofocus: 'autofocus'
    },
    {
      text: 'Cancel'
    }
  ]
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>

<div id="dialog" title="Basic dialog">
  This is some text.
  <br/>
  <a href="www.google.com">This is a link.</a>
  <br/>
  <input value="This is a textbox.">
</div>
1
Sam

Je cherchais un problème différent, mais la même cause. Le problème est que la boîte de dialogue active le premier <a href="">.</a> il trouve. Donc, si vous avez beaucoup de texte dans votre boîte de dialogue et que des barres de défilement apparaissent, vous pourriez être dans une situation où la barre de défilement sera défilée vers le bas. Je crois que cela résout également la question des premières personnes. Bien que les autres aussi.

Le simple facile à comprendre correctif. <a id="someid" href="#">.</a> comme première ligne de votre div de dialogue.

EXEMPLE:

 <div id="dialogdiv" title="some title">
    <a id="someid" href="#">.</a>
    <p>
        //the rest of your stuff
    </p>
</div>

Où votre dialogue est initié

$(somediv).dialog({
        modal: true,
        open: function () { $("#someid").hide(); otherstuff or function },
        close: function () { $("#someid").show(); otherstuff or function }
    });

Ce qui précède n'aura rien de ciblé et les barres de défilement resteront en haut, là où elles appartiennent. Le <a> obtient le focus mais est ensuite caché. Donc, l'effet global est l'effet souhaité.

Je sais que c'est un vieux fil de discussion, mais en ce qui concerne la documentation de l'interface utilisateur, il n'y a pas de solution. Cela ne nécessite pas de flou ou de mise au point pour fonctionner. Je ne sais pas si c'est le plus élégant. Mais cela a du sens et est facile à expliquer à quiconque.

1
MikeF

J'ai le même problème. J'ouvre une boîte de dialogue d'erreur lorsque la validation échoue et que le focus est saisi, comme l'indique Flugan dans sa réponse . Le problème est que même si aucun élément à l'intérieur de la boîte de dialogue n'est tabable, la boîte de dialogue elle-même est toujours focalisée. Voici le code d'origine non modifié de jquery-ui-1.8.23\js\jquery.ui.dialog.js:

// set focus to the first tabbable element in the content area or the first button
// if there are no tabbable elements, set focus on the dialog itself
$(self.element.find(':tabbable').get().concat(
  uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
    uiDialog.get()))).eq(0).focus();

Le commentaire leur appartient!

C'est vraiment mauvais pour moi pour plusieurs raisons. Le plus ennuyeux, c’est que la première réaction de l’utilisateur consiste à appuyer sur la touche arrière pour supprimer le dernier caractère, mais au lieu de cela, il est invité à quitter la page, car la touche arrière est enfoncée en dehors d’un contrôle de saisie.

J'ai trouvé que la solution suivante fonctionnait plutôt bien pour moi:

jqueryFocus = $.fn.focus;
$.fn.focus = function (delay, fn) {
  jqueryFocus.apply(this.filter(':not(.ui-dialog)'), arguments);
};
1
mark

A mon avis cette solution est très gentille:

$("#dialog").dialog({
    open: function(event, ui) {
        $("input").blur();
    }
});

Trouvé ici: impossible à supprimer-autofocus-in-ui-dialog

1
emolah

J'avais le même problème et le résolvais en insérant une entrée vide avant le sélecteur de date, qui dérobe le focus chaque fois que la boîte de dialogue est ouverte. Cette entrée est masquée à chaque ouverture de la boîte de dialogue et ré-affichée à la fermeture.

1
Manuel Leuenberger

Cela peut être un comportement du navigateur et non un problème de plug-in jQuery. Avez-vous essayé de supprimer le focus par programme après avoir ouvert la fenêtre contextuelle?.

$('#lnkAddReservation').click(function () {
    dlg.dialog('open');

    // you may want to change the selector below
    $('input,textarea,select').blur();

    return false;
});

Je n'ai pas testé ça mais ça devrait marcher.

1
RaYell

J'ai le même problème.

La solution de contournement que j'ai faite consiste à ajouter la zone de texte factice en haut du conteneur de dialogue.

<input type="text" style="width: 1px; height: 1px; border: 0px;" />
0
TTCG

Comme mentionné précédemment, il s’agit d’un bogue connu de jQuery UI et qui devrait être corrigé assez rapidement. Jusque là...

Voici une autre option, pour que vous n'ayez pas à vous soucier de tabindex:

Désactivez temporairement le sélecteur de date jusqu'à ce que la boîte de dialogue s'ouvre:

dialog.find(".datepicker").datepicker("disable");
dialog.dialog({
    "open": function() {$(this).find(".datepicker").datepicker("enable");},
});

Travaille pour moi.

Question en double: Comment brouiller la première entrée de formulaire lors de l'ouverture du dialogue

0
BMiner

Ceci est très important pour les smartphones et les tablettes, car le clavier apparaît lorsqu'une entrée est activée. C'est ce que j'ai fait, ajoutez cette entrée au début du div:

<input type="image" width="1px" height="1px"/>

Ne fonctionne pas avec la taille 0px. Je suppose que c'est encore mieux avec une vraie image transparente, soit .png ou .gif mais je n'ai pas essayé.

Fonctionne bien jusqu'à présent sur iPad.

0
Ángel Arbeteta

J'ai eu un problème similaire et je l'ai résolu en me concentrant sur le dialogue après ouverture:

var $dialog = $("#pnlFiltros")
    .dialog({
        autoOpen: false,
        hide: "puff",                   
        width: dWidth,
        height: 'auto',
        draggable: true,
        resizable: true,
        closeOnScape : true,
        position: [x,y]                    
    });
$dialog.dialog('open');
$("#pnlFiltros").focus(); //focus on the div being dialogued (is that a word?)

Mais dans mon cas, le premier élément est une ancre, donc je ne sais pas si cela laissera le sélecteur de date ouvert.

EDIT: ne fonctionne que sur IE

0
daniloquio

J'ai eu le même problème. Sur ma page, la première entrée est une zone de texte avec le calendrier jQuery UI. Le deuxième élément est le bouton. Comme la date a déjà de la valeur, je mets l'accent sur le bouton, mais j'ajoute d'abord un déclencheur pour la zone de texte flou. Cela résout le problème dans tous les navigateurs et probablement dans toutes les versions de jQuery. Testé en version 1.8.2.

<div style="padding-bottom: 30px; height: 40px; width: 100%;">
@using (Html.BeginForm("Statistics", "Admin", FormMethod.Post, new { id = "FormStatistics" }))
{
    <label style="float: left;">@Translation.StatisticsChooseDate</label>
    @Html.TextBoxFor(m => m.SelectDate, new { @class = "js-date-time",  @tabindex=1 })
    <input class="button gray-button button-large button-left-margin text-bold" style="position:relative; top:-5px;" type="submit" id="ButtonStatisticsSearchTrips" value="@Translation.StatisticsSearchTrips"  tabindex="2"/>
}
<script type="text/javascript">
$(document).ready(function () {        
    $("#SelectDate").blur(function () {
        $("#SelectDate").datepicker("hide");
    });
    $("#ButtonStatisticsSearchTrips").focus();

});   
0
user1698635

trouver dans jquery.ui.js

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(); 

et remplacer par

d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(-1).focus();
0
user1443069

Pour développer certaines des réponses précédentes (en ignorant l'aspect du sélecteur de date auxiliaire), si vous souhaitez empêcher l'événement focus() de focaliser le premier champ de saisie lorsque votre boîte de dialogue s'ouvre, essayez ceci:

$('#myDialog').dialog(
    { 'open': function() { $('input:first-child', $(this)).blur(); }
});
0
nickb

jQuery 1.9 est publié et il ne semble pas y avoir de solution. Tenter d'empêcher la focalisation de la première zone de texte par certaines des méthodes suggérées ne fonctionne pas dans la version 1.9. Je pense que parce que les méthodes tentent de brouiller la mise au point ou de la déplacer, APRÈS que la zone de texte de la boîte de dialogue ait déjà fait la mise au point et qu’elle ait fait son sale boulot.

Je ne vois rien dans la documentation de l'API qui me donne à penser que quelque chose a changé en termes de fonctionnalités attendues. Désactivé pour ajouter un bouton d'ouverture ...

0
pixelda