jQuery: clic de feu () avant l'événement blur ()

134

J'ai un champ de saisie dans lequel j'essaye de faire une suggestion de saisie semi-automatique. Le code ressemble à

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

Lors de l' blur()événement d'entrée, je veux masquer le div des résultats:

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

Lorsque j'écris quelque chose dans mon entrée, j'envoie une requête au serveur et j'obtiens une réponse json, je l'analyse dans la structure ul-> li et je mets cet ul dans mon #myresultsdiv.

Lorsque je clique sur cet élément li analysé, je veux définir la valeur de li à l'entrée et masquer #myresultsdiv

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

Tout va bien, mais lorsque je clique sur mon blur()événement li se déclenche avant click()et que la valeur d'entrée n'obtient pas le html de li.

Comment puis-je organiser un click()événement avant blur()?

Egor Sazanovich
la source
alors ce cas pourquoi vous utilisez la fonction de flou? lorsque votre besoin est déjà rempli à partir de la fonction de clic.
Owais Iqbal
Cela ne changera probablement pas l'ordre dans lequel vos événements se déclenchent, mais si blurest vraiment déclenché après avoir cliqué sur un li, vous n'avez probablement pas besoin d'exécuter $("#myresults").hide()dans le gestionnaire de clics. Il semble que ce soit en train de $(this).html()renvoyer une chaîne vide. Pourriez-vous logou alert $(this).html()pour vous en assurer?
veeTrain
@OwaisIqbal parfois il n'y a aucun résultat, parfois l'utilisateur ne veut rien sélectionner parmi les suggestions, parfois l'utilisateur ne veut plus utiliser cette entrée, mais je dois cacher le résultat inutilisé
Egor Sazanovich
@veeTrain il y a beaucoup d'actions dans mes gestionnaires, je viens de les minimiser pour comprendre facilement le problème dans ma question. ps J'ai essayé d'ajouter un point de surveillance dans Firebug blur()et les click()gestionnaires, il n'y a pas d'action après la blur()fin
Egor Sazanovich
Il semble que vous deviez mettre les fonctions en file d'attente. Essayez de jeter un œil à cette page: stackoverflow.com/questions/1058158/… . La partie premier entré, premier sorti (FIFO) peut vous concerner
Patriotec

Réponses:

312

Solution 1

Écoutez mousedownplutôt que click.

Les événements mousedownet blurse produisent l'un après l'autre lorsque vous appuyez sur le bouton de la souris, mais clickuniquement lorsque vous le relâchez.

Solution 2

Vous pouvez preventDefault()en mousedownbloquer le menu déroulant de voler le focus. Le léger avantage est que la valeur sera sélectionnée lorsque le bouton de la souris sera relâché, ce qui correspond au fonctionnement des composants de sélection natifs. 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
la source
12
La solution 1 a fonctionné pour moi dans cette même situation! Changement facile! Merci :)
Jon
Merci :) Mais pouvez-vous expliquer pourquoi écouter mousedown au lieu de cliquer fonctionne comme du charme?
Mudassir Ali
3
@MudassirAli parce que l'événement mousedown vient avant le flou et le clic vient après. jsfiddle.net/f3BKP
Alexey Lebedev
La solution n ° 1 est à mon avis le meilleur choix. Simple et efficace. Timeout signifierait plus à coder + plus de place pour un comportement inattendu (combien de temps un timeout? Assez long pour enregistrer le clic, mais pas trop longtemps pour confondre l'utilisation ...).
cw24
5
La solution n ° 2 est ingénieuse. Je ne l'aurais jamais compris! Merci
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();
}

VIOLON

adeneo
la source
2

J'ai rencontré ce problème et l'utilisation mousedownn'est pas une option pour moi.

J'ai résolu cela en utilisant setTimeoutla fonction de gestionnaire

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

Je viens de répondre à une question similaire: https://stackoverflow.com/a/46676463/227578

Une alternative aux solutions mousedown est de lui faire ignorer les événements de flou provoqués en cliquant sur des éléments spécifiques (c'est-à-dire, dans votre gestionnaire de flou, ignorez l'exécution si c'est le résultat d'un clic sur un élément spécifique).

$("#myinput").live('blur',function(e){
     if (!e.relatedTarget || !$(e.relatedTarget).is("#myresults ul li")) {
         $("#myresults").hide();
     }
});
dule
la source
dans mon cas, event.relatedTarget renvoie null, une idée pourquoi cela pourrait-il être?
gaurav5430
ok, j'ai la réponse ici: stackoverflow.com/questions/42764494/…
gaurav5430
0

Les solutions Mousedown ne fonctionnent pas pour moi, lorsque je clique sur des éléments non bouton. Voici donc ce que j'ai fait avec la fonction de flou dans mon code:

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