jQuery: aciona o clique () antes do evento blur ()

134

Eu tenho um campo de entrada, onde tento fazer sugestões de preenchimento automático. Código parece

<input type="text" id="myinput">
<div id="myresults"></div>

No blur()evento de entrada, quero ocultar a div dos resultados:

$("#myinput").live('blur',function(){
     $("#myresults").hide();
});

Quando escrevo algo em minha entrada, envio solicitação para o servidor e obtenho resposta json, analise-a na estrutura ul-> li e coloque essa ul na minha #myresultsdiv.

Quando clico nesse elemento li analisado, desejo definir o valor de li para inserir e ocultar #myresultsdiv

$("#myresults ul li").live('click',function(){
     $("#myinput").val($(this).html());
     $("#myresults").hide();
});

Tudo está indo bem, mas quando clico no meu blur()evento li é acionado antes click()e o valor da entrada não recebe o html do li.

Como posso configurar o click()evento antes blur()?

Egor Sazanovich
fonte
Nesse caso, por que você usa a função de desfoque? quando sua necessidade já estiver preenchida a partir da função de clique.
Owais Iqbal
Provavelmente, isso não altera a ordem em que seus eventos estão sendo disparados, mas se blurrealmente estiver disparando após você clicar em um li, provavelmente não precisará executar $("#myresults").hide()no manipulador de cliques. O que parece estar acontecendo é que $(this).html()está retornando uma string vazia. Você poderia logou alert $(this).html()para ter certeza?
VeeTrain 18/05
@OwaisIqbal às vezes não há nenhum resultado, por vezes, o usuário não quiser selecionar qualquer coisa de sugestões, por vezes, o usuário não quiser usar esta entrada mais, mas devo esconder resultado não utilizado
Egor Sazanovich
@veeTrain, existem muitas ações em meus manipuladores, eu as minimizei para facilitar a compreensão do problema na minha pergunta. ps Eu tentei adicionar o ponto de controle no firebug blur()e nos click()manipuladores, não há ações após o blur()término
Egor Sazanovich 18/12/12 /
Parece que você precisa enfileirar as funções. Tente dar uma olhada nesta página: stackoverflow.com/questions/1058158/… . A parte First-In-First-Out (FIFO) pode pertencer a você
Patriotec

Respostas:

312

Solução 1

Ouça em mousedownvez declick .

Os eventos mousedowne blurocorrem um após o outro quando você pressiona o botão do mouse, masclick somente quando você o libera.

Solução 2

Você pode preventDefault()em mousedownbloquear o menu suspenso de roubar foco. A pequena vantagem é que o valor será selecionado quando o botão do mouse for liberado, e é assim que os componentes de seleção nativos funcionam. JSFiddle

$('input').on('focus', function() {
    $('ul').show();
}).on('blur', function() {
    $('ul').hide();
});

$('ul').on('mousedown', function(event) {
    event.preventDefault();
}).on('click', 'li', function() {
    $('input').val(this.textContent).blur();
});
Alexey Lebedev
fonte
12
A solução 1 funcionou para mim nesta mesma situação! Mudança fácil! Obrigado :)
Jon
Obrigado :) Mas você pode explicar por que ouvir a ratoeira em vez de clicar funciona como um encanto?
Mudassir Ali
3
@MudassirAli, porque o evento da ratoeira ocorre antes do desfoque e o clique vem depois. jsfiddle.net/f3BKP
Alexey Lebedev
A solução 1 é, na minha opinião, a melhor escolha. Simples e eficaz. O tempo limite significaria mais código + mais espaço para comportamento inesperado (quanto tempo decorrido? Tempo suficiente para registrar o clique, mas não muito tempo para confundir o uso ...).
Cw24
5
A solução 2 é engenhosa. Eu nunca teria descoberto! Obrigado
Tobia
2
$(document).on('blur', "#myinput", hideResult);

$(document).on('mousedown', "#myresults ul li", function(){
     $(document).off('blur', "#myinput", hideResult); //unbind the handler before updating value
     $("#myinput").val($(this).html()).blur(); //make sure it does not have focus anymore
     hideResult(); 
     $(document).on('blur', "#myinput", hideResult);  //rebind the handler if needed
});

function hideResult() {
     $("#myresults").hide();
}

FIDDLE

adeneo
fonte
2

Eu enfrentei esse problema e usando mousedown não é uma opção para mim.

Eu resolvi isso usando setTimeoutna função manipulador

        elem1.on('blur',function(e) {

            var obj = $(this);

            // Delay to allow click to execute
            setTimeout(function () {
                if (e.type == 'blur') {

                  // Do stuff here

                }
            }, 250);
        });

        elem2.click( function() {
            console.log('Clicked');
        });
geckob
fonte
2

Acabei de responder uma pergunta semelhante: https://stackoverflow.com/a/46676463/227578

Uma alternativa para as soluções de redução do mouse é ignorar os eventos de desfoque causados ​​ao clicar em elementos específicos (ou seja, no seu manipulador de desfoque, pule a execução se for o resultado de clicar em um elemento específico).

$("#myinput").live('blur',function(e){
     if (!e.relatedTarget || !$(e.relatedTarget).is("#myresults ul li")) {
         $("#myresults").hide();
     }
});
dule
fonte
no meu caso, event.relatedTarget retorna nulo, alguma idéia de por que isso poderia ser?
gaurav5430
ok, tenho a resposta aqui: stackoverflow.com/questions/42764494/… #
gaurav5430
0

As soluções Mousedown não funcionam para mim quando clico em elementos que não são botões. Então, aqui está o que eu fiz com a função blur no meu código:

.on("blur",":text,:checkbox,:radio,select",function() {
/*
* el.container 
* container, you want detect click function on.
*/
            var outerDir = el.container.find(':hover').last();
            if (outerDir.length) {
                if ($.inArray(outerDir.prop('tagName'), ["A","SELECT"] ) != -1 || outerDir.prop('type') == 'button' || outerDir.prop('type') == 'submit') {
                    outerDir.click();
                }
                if (outerDir.prop('type') == 'checkbox') {
                    outerDir.change();
                }
                return false;
            }
/*          
* YOUR_BLUR_FUNCTION_HERE;
*/
});
Andriy
fonte