Impedir que a caixa de diálogo jQuery UI defina o foco para a primeira caixa de texto


156

Eu configurei uma caixa de diálogo modal da interface do usuário do jQuery para exibir quando um usuário clica em um link. Existem duas caixas de texto (mostro apenas o código 1 por questões de concisão) nessa tag div de diálogo e ela é alterada para ser uma caixa de texto jQuery UI DatePicker que reage ao foco.

O problema é que a caixa de diálogo da interface do usuário do jQuery ('open') aciona a primeira caixa de texto para focar, o que aciona o calendário do datepicker para abrir imediatamente.

Então, estou procurando uma maneira de impedir que o foco aconteça automaticamente.

<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>

ele definirá o foco até para uma imagem! tanto para tags <img> regulares - quanto para <input type = image> #
Simon_Weaver

Respostas:


78

O registro de alterações da interface do usuário do jQuery 1.10.0 lista o ticket 4731 como sendo corrigido.

Parece que o focusSelector não foi implementado, mas uma pesquisa em cascata de vários elementos foi usada. Do bilhete:

Estenda o foco automático, começando com [foco automático] e, em seguida: conteúdo com tabulação, botão e botão de fechar, botão de fechar e caixa de diálogo

Portanto, marque um elemento com o autofocusatributo e esse é o elemento que deve receber o foco:

<input autofocus>

Na documentação , a lógica do foco é explicada (logo abaixo do índice, sob o título 'Foco'):

Ao abrir uma caixa de diálogo, o foco é automaticamente movido para o primeiro item que corresponde ao seguinte:

  1. O primeiro elemento na caixa de diálogo com o autofocusatributo
  2. O primeiro :tabbableelemento dentro do conteúdo da caixa de diálogo
  3. O primeiro :tabbableelemento no botão da caixa de diálogo
  4. O botão Fechar da caixa de diálogo
  5. O próprio diálogo

Para que serve o voto negativo? Se foi porque listei 1,9 como a versão de correção, atualizei para 1,10 para corresponder ao ticket.
Slolife 12/12/12

1
Estou olhando a documentação do jquery-ui 1.10 para o Dialog e não estou vendo. Eu procurei por "focusSelector" na API e ela não está lá.
Paul Tomblin 26/03

3
Definir o foco para qualquer elemento que está fora da tela rola a janela para cima ou para baixo até esse elemento, e isso acontece sempre que a janela fica em foco, não apenas na caixa de diálogo aberta. Se eu usar o Firebug para "inspecionar elemento" e clicar novamente na janela do documento, minha janela rolará para cima ou para baixo para o elemento em que a jQuery-UI estiver focada. A questão não é como escolher qual elemento obtém o foco, mas como evitar o foco. Escolher um elemento diferente para focar não resolveria o problema.
Vladimir Kornea

4
A idéia de que a interface do usuário do jQuery considere isso 'fixo' é louca. A correção é remover completamente qualquer lógica de foco automático. Pedi para você abrir uma caixa de diálogo, não se concentrar em uma entrada. Tão irritante.
AJB

2
fwiw, adicionei uma entrada com tipo = "oculto" acima da primeira entrada e adicionei o atributo de foco automático a ela. Não significa o que você pensa que significa, mas funciona para corrigir esse problema.
precisa saber é o seguinte

77

Adicione um espaço oculto acima dele, use ui-helper-hidden-affordable para torná-lo oculto por posicionamento absoluto. Eu sei que você tem essa classe porque está usando o diálogo do jquery-ui e está no jquery-ui.

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

1
Ótimo trabalho. Nenhum js é necessário, não altera o layout e o jquery ui o suporta nativamente.
steampowered

Concordo, ótimo trabalho. Também é bom saber sobre a classe de acesso oculto! Obrigado!!
user1055761

4
Isso causa problemas para as pessoas que utilizam tecnologia de assistência (por exemplo, leitores de tela)
rink.attendant.6

1
@ rink.attendant.6 quais problemas?
oxfn

solução incrível
Pedro Coelho

63

Na interface do usuário do jQuery> = 1.10.2, você pode substituir o _focusTabbablemétodo do protótipo por uma função placebo:

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

Violino

Isso afetará todos os dialogs na página sem a necessidade de editar cada um manualmente.

A função original não faz nada além de definir o foco para o primeiro elemento com autofocusatributo / tabbableelemento / ou retornar ao próprio diálogo. Como seu uso está apenas focando um elemento, não deve haver problema em substituí-lo por um noop.


7
Horas e horas e horas e horas queimavam nisso. Meu cliente agradece.
Lamarant 24/03

1
Essa deve ser a resposta!
Brianol

2 dias procuramos por essas soluções ... nada mais funcionou ... Muito obrigado!
Legionar

1
Aviso: quando a caixa de diálogo aparecer, pressionar a tecla Escape não fechará a caixa de diálogo (até você focar a caixa de diálogo).
Robert

1
@Robert, em vez de substituí-lo por $.noop, substitua-o por uma função que anote a caixa de diálogo ativa e registre um manipulador de eventos de chave global que intercepte ESCe feche a caixa de diálogo 'ativa', se houver uma.
Perkins

28

A partir do jQuery UI 1.10.0, você pode escolher em qual elemento de entrada focar usando o foco automático do atributo HTML5 .

Tudo o que você precisa fazer é criar um elemento fictício como sua primeira entrada na caixa de diálogo. Absorverá o foco para você.

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

Isso foi testado no Chrome, Firefox e Internet Explorer (todas as versões mais recentes) em 7 de fevereiro de 2013.

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


27

Eu encontrei o seguinte código na função de diálogo da interface do usuário do jQuery para abrir.

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

Você pode solucionar o comportamento do jQuery ou alterar o comportamento.

tabindex -1 funciona como uma solução alternativa.


1
Tabindex = -1 não me impede de tabular para a caixa de texto?
Slolife 29/07/09

2
Obrigado pela pesquisa. Agora eu sei que é o código real que está fazendo isso. Talvez eu faça uma sugestão para a equipe da interface do usuário do jQuery para adicionar uma opção para desativar esse foco automático.
Slolife 29/07/09

3
@slolife - Desculpe ressuscitar esse segmento realmente antigo, mas esse tíquete diz que a correção (a focusSelectoropção) deve estar no jQueryUI 1.8, e agora estamos na 1.8.13 e não a vejo nos documentos da caixa de diálogo do jQueryUI . O que aconteceu com isso?
precisa

Deixa pra lá. Eu tinha visto "Milestone alterado de TBD para 1,8" no histórico de modificações e não havia percebido que na verdade diz 1,9 no topo.
precisa

Eu tenho um problema semelhante, minha solução alternativa é descrita aqui - stackoverflow.com/a/12250193/80002
marca

15

Apenas descobri isso enquanto brincava.

Eu descobri com essas soluções para remover o foco, fazendo com que a ESCchave parasse de funcionar (por exemplo, feche a caixa de diálogo) ao entrar pela primeira vez no Diálogo.

Se a caixa de diálogo for aberta e você pressionar imediatamente ESC, ela não será fechada (se você a tiver ativado), porque o foco está em algum campo oculto ou algo assim e não está recebendo eventos de pressionamento de tecla.

A maneira como eu o corrigi foi adicionar isso ao evento aberto para remover o foco do primeiro campo:

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

Isso define o foco na caixa de diálogo, que não é visível, e a ESCchave funciona.


3
Essa parece a única solução que funciona, que não inclui a adição de HTML inútil, a remoção do tabindex ou a quebra da chave ESC.
Bojan Bedrač

10

Defina o tabindex da entrada como -1 e, em seguida, defina dialog.open para restaurar o tabindex, se necessário posteriormente:

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

4
Tabindex = -1 não me impede de tabular para a caixa de texto?
Slolife 29/07/09

1
u poderia usar um setTimeout para definir a volta tabindex após o diálogo é mostrada
redsquare

10

Minha solução alternativa:

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

+1. Funciona como um encanto usando o :firstseletor ou .first()no FF / Chrome / IE9. Jogá-lo na dialogopenligação também funciona.
30/12

Este me levou lá também. Exceto comigo, meu diálogo não tinha entradas em tudo, e a primeira ligação foi ficando foco ... então eu adicionei esta opção para o meu diálogo jQuery:open: function(){ $('a').blur(); // no autofocus on links }
Marcus

8

Eu tinha um conteúdo que era mais longo que o diálogo. Ao abrir, a caixa de diálogo passaria para a primeira: tabbable que estava na parte inferior. Aqui estava a minha correção.

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

Isso funcionou para mim, mas eu usei em $('...').blur();vez de rolar.
Jawa

4
Meu conteúdo também foi muito longo. O borrão removeu a seleção, mas deixou a caixa de diálogo rolada para baixo. scrollTop rolou o conteúdo para o topo, mas saiu da seleção. Acabei usando $ ('...'). Blur (); $ (this) .scrollTop (0); trabalhou como um campeão.

7

Solução simples:

Basta criar um elemento invisível com tabindex = 1 ... Isso não focalizará o datepicker ...

por exemplo.:

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

Funciona bem no ie9 e no firefox, mas não no safari / chrome.
tuseau 23/07/12

3

Aqui está a solução que eu implementei depois de ler o ticket jQuery UI # 4731 , originalmente publicado por slolife como resposta a outra resposta. (O ticket também foi criado por ele.)

Primeiro, em qualquer método usado para aplicar preenchimentos automáticos à página, adicione a seguinte linha de código:

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

Isso desativa o comportamento de "foco automático" do jQuery. Para garantir que seu site continue sendo amplamente acessível, agrupe seus métodos de criação de diálogo para que código adicional possa ser adicionado e adicione uma chamada para focar o primeiro elemento de entrada:

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

}

Para abordar ainda mais a acessibilidade quando as opções de preenchimento automático são selecionadas via teclado, substituímos o retorno de chamada de preenchimento automático "select" da jQuery UI e adicionamos algum código adicional para garantir que o textElement não perca o foco no IE 8 após fazer uma seleção.

Aqui está o código que usamos para aplicar preenchimentos automáticos a elementos:

$.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;
}

2

Você pode fornecer essa opção para focar o botão Fechar.

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

1

Esse pode ser um comportamento do navegador, não um problema do plugin jQuery. Você tentou remover o foco programaticamente depois de abrir o pop-up.

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

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

    return false;
});

Ainda não testei isso, mas deve funcionar ok.


1
infelizmente isso não funciona. não tenho certeza se é uma coisa do IE ou da UI da jquery. mas mesmo se você mover o foco para outra coisa programaticamente, o calendário permanecerá aberto.
Patricia

1

Eu tive o mesmo problema e o resolvi inserindo uma entrada vazia antes do datepicker, que rouba o foco toda vez que a caixa de diálogo é aberta. Esta entrada está oculta em todas as aberturas da caixa de diálogo e é mostrada novamente no fechamento.


1

Bem, é legal que ninguém tenha encontrado a solução no momento, mas parece que tenho algo para você. A má notícia é que o diálogo se concentra em qualquer caso, mesmo que não haja entradas e links. Eu uso a caixa de diálogo como uma dica de ferramenta e definitivamente preciso que o foco permaneça no elemento original. Aqui está a minha solução:

use a opção [autoOpen: false]

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

Enquanto a caixa de diálogo é invisível, o foco não é definido em nenhum lugar e permanece no local original. Ele funciona para dicas de ferramentas com apenas um texto simples, mas não testado para diálogos mais funcionais, onde pode ser importante ter um diálogo visível no momento da abertura. Provavelmente funcionará bem em qualquer caso.

Entendo que a postagem original era apenas para evitar o foco no primeiro elemento, mas você pode facilmente decidir onde o foco deve estar após a caixa de diálogo ser aberta (após o meu código).

Testado no IE, FF e Chrome.

Espero que isso ajude alguém.



1

Eu tenho um problema similar. Abro uma caixa de diálogo de erro quando a validação falha e ela agarra o foco, assim como Flugan mostra em sua resposta . O problema é que, mesmo que nenhum elemento dentro da caixa de diálogo possa ser tabulado, a própria caixa de diálogo ainda estará focada. Aqui está o código não minificado original 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();

O comentário é deles!

Isso é muito ruim para mim por várias razões. O mais irritante é que a primeira reação do usuário é bater no backspace para excluir o último caractere, mas, em vez disso, ele é solicitado a sair da página, porque o backspace é atingido fora de um controle de entrada.

Descobri que a seguinte solução alternativa funciona muito bem para mim:

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

Isso pode ser estendido para afetar apenas caixas de diálogo específicas usando a opção 'dialogClass' em .dialog () e alterando o filtro acima: not para incluir sua classe. por exemplo: não (.ui-dialog.myDialogClass)
Andrew Martinez

1

Eu estava procurando um problema diferente, mas com a mesma causa. A questão é que o diálogo define o foco para o primeiro <a href="">.</a>que encontrar. Portanto, se você tiver muito texto na caixa de diálogo e as barras de rolagem aparecerem, poderá ter a situação em que a barra de rolagem será rolada para baixo. Eu acredito que isso também resolve a questão das primeiras pessoas. Embora os outros também o façam.

A correção simples e fácil de entender. <a id="someid" href="#">.</a> como a primeira linha na sua caixa de diálogo div.

EXEMPLO:

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

Onde sua caixa de diálogo é iniciada

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

O item acima não terá nada em foco e as barras de rolagem permanecerão no topo a que pertencem. O <a>foco fica mas fica oculto. Portanto, o efeito geral é o efeito desejado.

Eu sei que este é um thread antigo, mas, quanto aos documentos da interface do usuário, não há solução para isso. Isso não requer desfoque ou foco para funcionar. Não tenho certeza se é o mais elegante. Mas isso faz sentido e é fácil de explicar para qualquer pessoa.


1

Se você tiver apenas um campo na forma de caixa de diálogo Jquery e for o que precisa do Datepicker, como alternativa, basta definir o foco no botão Fechar (cruz) da caixa de diálogo na barra de título da caixa de diálogo:

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

Chamar esta caixa de diálogo APÓS foi inicializada, por exemplo:

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

Porque o botão Fechar é renderizado após o .dialog()chamado.


1

Se você estiver usando botões de diálogo, basta definir o autofocusatributo em um dos botões:

$('#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>


0

Eu tenho o mesmo problema.

A solução alternativa que fiz foi adicionar a caixa de texto fictícia na parte superior do contêiner de diálogo.

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

0

Como mencionado, este é um bug conhecido da interface do usuário do jQuery e deve ser corrigido relativamente em breve. Até então...

Aqui está outra opção, para que você não precise mexer com tabindex:

Desative o selecionador de datas temporariamente até que a caixa de diálogo seja aberta:

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

Funciona para mim.

Pergunta duplicada: Como desfocar a primeira entrada de formulário na abertura da caixa de diálogo


0

Para expandir algumas das respostas anteriores (e ignorar o aspecto auxiliar do comparador de datas), se você deseja impedir que o focus()evento concentre o primeiro campo de entrada quando a caixa de diálogo for aberta, tente o seguinte:

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

0

Eu tive um problema semelhante e o resolvi, concentrando-me no diálogo após aberto:

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?)

Mas no meu caso, o primeiro elemento é uma âncora, então não sei se, no seu caso, isso deixará o datepicker aberto.

EDIT: só funciona no IE


0

localize em jquery.ui.js

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

e substitua por

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

0

O jQuery 1.9 é lançado e não parece haver uma correção. Tentar impedir o foco da primeira caixa de texto por alguns dos métodos sugeridos não está funcionando no 1.9. Acho que porque os métodos tentam desfocar o foco ou mover o foco ocorrem APÓS a caixa de texto na caixa de diálogo já ter ganhado foco e feito seu trabalho sujo.

Não vejo nada na documentação da API que me faça pensar que algo mudou em termos de funcionalidade esperada. Desligado para adicionar um botão de abertura ...


A correção agora foi empurrado para 1,10 de acordo com o bilhete jQuery: bugs.jqueryui.com/ticket/4731
slolife

0

Eu tive um problema semelhante. Na minha página, a primeira entrada é uma caixa de texto com o calendário da UI do jQuery. O segundo elemento é o botão. Como a data já tem valor, defino o botão de foco, mas primeiro adicione gatilho para desfoque na caixa de texto. Isso resolve o problema em todos os navegadores e provavelmente em todas as versões do jQuery. Testado na versão 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

Isso é realmente importante para smartphones e tablets, porque o teclado aparece quando uma entrada tem o foco. Isto é o que eu fiz, adicione esta entrada no início da div:

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

Não funciona com tamanho 0px. Eu acho que é ainda melhor com uma imagem transparente real, .pngou não, .gifmas ainda não tentei.

Até agora, está funcionando bem no iPad.


-1

Você pode adicionar isso:

...

dlg.dialog({ autoOpen:false,
modal: true, 
width: 400,
open: function(){                  // There is new line
  $("#txtStartDate").focus();
  }
});

...


3
Ele está perguntando como impedir o foco, não adicionar o foco.
CBarr

-2

como primeira entrada: <input type="text" style="position:absolute;top:-200px" />

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.