web-dev-qa-db-fra.com

Détection de la saisie automatique du navigateur

Comment savoir si un navigateur a automatiquement rempli une zone de texte? Surtout avec les zones nom d'utilisateur et mot de passe qui se remplissent automatiquement autour du chargement de page.

Ma première question est de savoir quand cela se produit dans la séquence de chargement de la page. Est-ce avant ou après document.ready?

Deuxièmement, comment puis-je utiliser la logique pour savoir si cela s'est produit? Ce n'est pas que je veuille empêcher cela, mais simplement participer à l'événement. De préférence quelque chose comme ceci:

if (autoFilled == true) {

} else {

}

Si possible, j'aimerais beaucoup voir un commentaire montrant votre réponse.

Doubles possibles

Événement DOM pour la saisie automatique du mot de passe du navigateur?

Remplissage automatique du navigateur et événements déclenchés par Javascript

- Ces questions n'expliquent pas vraiment quels événements sont déclenchés, elles vérifient simplement en permanence la zone de texte (ce qui n'est pas bon pour la performance!).

132
Undefined

Le problème est que le remplissage automatique est géré différemment par différents navigateurs. Certains envoient l'événement de changement, d'autres non. Il est donc presque impossible de s’accrocher à un événement qui est déclenché lorsque le navigateur remplit automatiquement un champ de saisie.

  • Changer le déclencheur d'événement pour différents navigateurs:

    • Pour les champs nom d'utilisateur/mot de passe:

      1. Firefox 4, IE 7 et IE 8 ne distribuent pas l'événement de modification.
      2. Safari 5 et Chrome 9 envoient l'événement de modification.
    • Pour les autres champs de formulaire:

      1. IE 7 et IE 8 ne distribuent pas l'événement de modification.
      2. Firefox 4 distribue l'événement de changement de modification lorsque les utilisateurs sélectionnent une valeur dans une liste de suggestions et la retirent du champ.
      3. Chrome 9 n'envoie pas l'événement de modification.
      4. Safari 5 envoie l'événement de modification.

La meilleure solution consiste à désactiver la saisie semi-automatique pour un formulaire à l'aide de autocomplete="off" dans votre formulaire ou à interroger à intervalles réguliers pour voir s'il est rempli.

Pour votre question sur si elle est remplie avant ou sur document.ready, cela varie d’un navigateur à l’autre et même d’une version à l’autre. Pour les champs nom d'utilisateur/mot de passe uniquement lorsque vous sélectionnez un nom d'utilisateur, le mot de passe est rempli. Donc, dans l’ensemble, vous auriez un code très confus si vous essayez de vous attacher à n’importe quel événement.

Vous pouvez avoir une bonne lecture sur ceci ICI

110
afrin216

Solution pour les navigateurs WebKit

Dans la documentation MDN pour la pseudo-classe CSS : -webkit-autofill CSS: 

La pseudo-classe CSS: -webkit-autofill CSS correspond quand un élément a sa valeur remplie automatiquement par le navigateur

Nous pouvons définir une règle vide transition css sur l'élément <input> désiré une fois qu'il est :-webkit-autofilled. JS pourra alors se connecter à l'événement animationstart.

Crédits à l’équipe Klarna UI . Voir leur implémentation Nice ici:

44
Lev Kazakov

Juste au cas où quelqu'un chercherait une solution (comme c'était le cas aujourd'hui), pour écouter un changement automatique du navigateur, voici une méthode jQuery personnalisée que j'ai construite, afin de simplifier le processus lors de l'ajout d'un écouteur de changement à une entrée:

    $.fn.allchange = function (callback) {
        var me = this;
        var last = "";
        var infunc = function () {
            var text = $(me).val();
            if (text != last) {
                last = text;
                callback();
            }
            setTimeout(infunc, 100);
        }
        setTimeout(infunc, 100);
    };

Vous pouvez l'appeler comme ça:

$("#myInput").allchange(function () {
    alert("change!");
});
15
LcSalazar

Cela fonctionne pour moi dans les derniers Firefox, Chrome et Edge:

$('#email').on('blur input', function() {
    ....
});
14
James

Pour Google Chrome autocomplete, cela a fonctionné pour moi:

if ($("#textbox").is(":-webkit-autofill")) 
{    
    // the value in the input field of the form was filled in with google chrome autocomplete
}
13
ThdK

Malheureusement, le seul moyen fiable que j’ai trouvé de vérifier ce navigateur croisé est d’interroger l’entrée. Pour le rendre réactif, écoutez également les événements. Chrome a commencé à masquer les valeurs de saisie automatique de javascript qui nécessite un piratage.

  • Sondage toutes les demi à troisièmes de seconde (n'a pas besoin d'être instantané dans la plupart des cas)
  • Déclenchez l'événement de changement à l'aide de JQuery, puis créez votre logique dans une fonction écoutant l'événement de changement.
  • Ajoutez un correctif pour les valeurs de mot de passe de saisie automatique masquées de Chrome.

    $(document).ready(function () {
        $('#inputID').change(YOURFUNCTIONNAME);
        $('#inputID').keypress(YOURFUNCTIONNAME);
        $('#inputID').keyup(YOURFUNCTIONNAME);
        $('#inputID').blur(YOURFUNCTIONNAME);
        $('#inputID').focusin(YOURFUNCTIONNAME);
        $('#inputID').focusout(YOURFUNCTIONNAME);
        $('#inputID').on('input', YOURFUNCTIONNAME);
        $('#inputID').on('textInput', YOURFUNCTIONNAME);
        $('#inputID').on('reset', YOURFUNCTIONNAME);
    
        window.setInterval(function() {
            var hasValue = $("#inputID").val().length > 0;//Normal
            if(!hasValue){
                hasValue = $("#inputID:-webkit-autofill").length > 0;//Chrome
            }
    
            if (hasValue) {
                $('#inputID').trigger('change');
            }
        }, 333);
    });
    
7
Bucket

Je lisais beaucoup de choses sur ce problème et je voulais fournir une solution très rapide qui m'aidait.

let style = window.getComputedStyle(document.getElementById('email'))
  if (style && style.backgroundColor !== inputBackgroundNormalState) {
    this.inputAutofilledByBrowser = true
  }

inputBackgroundNormalState pour mon modèle est 'rgb (255, 255, 255)'.

Ainsi, lorsque les navigateurs appliquent la saisie semi-automatique, ils ont tendance à indiquer que l'entrée est remplie automatiquement en appliquant une couleur jaune différente (gênante) sur l'entrée.

Edit: cela fonctionnera pour tous les navigateurs 

7
DrNio

Il existe un nouveau composant polyfill pour résoudre ce problème sur github. Regardez autofill-event . Il suffit de l'installer et voilà, le remplissage automatique fonctionne comme prévu.

bower install autofill-event
6
David

Je cherchais une chose semblable. Chrome uniquement ... Dans mon cas, la division de l'emballage devait savoir si le champ de saisie était rempli automatiquement. Je pourrais donc lui donner des CSS supplémentaires, comme le fait Chrome dans le champ de saisie lorsqu'il le remplit automatiquement. En regardant toutes les réponses ci-dessus, ma solution combinée était la suivante:

/* 
 * make a function to use it in multiple places
 */
var checkAutoFill = function(){
    $('input:-webkit-autofill').each(function(){
        $(this).closest('.input-wrapper').addClass('autofilled');
    });
}

/* 
 * Put it on the 'input' event 
 * (happens on every change in an input field)
 */
$('html').on('input', function() {
    $('.input-wrapper').removeClass('autofilled');
    checkAutoFill();
});

/*
 * trigger it also inside a timeOut event 
 * (happens after chrome auto-filled fields on page-load)
 */
setTimeout(function(){ 
    checkAutoFill();
}, 0);

Le code HTML pour que cela fonctionne serait

<div class="input-wrapper">
    <input type="text" name="firstname">
</div>
4
Julesezaar

Ma solution:

Écoutez les événements change comme vous le feriez normalement et procédez comme suit pour charger le contenu du DOM:

setTimeout(function() {
    $('input').each(function() {
        var elem = $(this);
        if (elem.val()) elem.change();
    })
}, 250);

Cela déclenchera les événements de modification pour tous les champs qui ne sont pas vides avant que l'utilisateur ait eu l'occasion de les modifier.

4
Camilo Martin

Sur Chrome, vous pouvez détecter les champs de remplissage automatique en définissant une règle CSS spéciale pour les éléments à remplissage automatique, puis en vérifiant avec javascript si la règle a été appliquée à l'élément.

Exemple:

CSS

input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 30px white inset;
}

JavaScript

  let css = $("#selector").css("box-shadow")
  if (css.match(/inset/))
    console.log("autofilled:", $("#selector"))
2
Pietro Coelho

J'ai la solution parfaite pour cette question, essayez cet extrait de code.
La démo est là

function ModernForm() {
    var modernInputElement = $('.js_modern_input');

    function recheckAllInput() {
        modernInputElement.each(function() {
            if ($(this).val() !== '') {
                $(this).parent().find('label').addClass('focus');
            }
        });
    }

    modernInputElement.on('click', function() {
        $(this).parent().find('label').addClass('focus');
    });
    modernInputElement.on('blur', function() {
        if ($(this).val() === '') {
            $(this).parent().find('label').removeClass('focus');
        } else {
            recheckAllInput();
        }
    });
}

ModernForm();
.form_sec {
  padding: 30px;
}
.form_sec .form_input_wrap {
  position: relative;
}
.form_sec .form_input_wrap label {
  position: absolute;
  top: 25px;
  left: 15px;
  font-size: 16px;
  font-weight: 600;
  z-index: 1;
  color: #333;
  -webkit-transition: all ease-in-out 0.35s;
  -moz-transition: all ease-in-out 0.35s;
  -ms-transition: all ease-in-out 0.35s;
  -o-transition: all ease-in-out 0.35s;
  transition: all ease-in-out 0.35s;
}
.form_sec .form_input_wrap label.focus {
  top: 5px;
  color: #a7a9ab;
  font-weight: 300;
  -webkit-transition: all ease-in-out 0.35s;
  -moz-transition: all ease-in-out 0.35s;
  -ms-transition: all ease-in-out 0.35s;
  -o-transition: all ease-in-out 0.35s;
  transition: all ease-in-out 0.35s;
}
.form_sec .form_input {
  width: 100%;
  font-size: 16px;
  font-weight: 600;
  color: #333;
  border: none;
  border-bottom: 2px solid #d3d4d5;
  padding: 30px 0 5px 0;
  outline: none;
}
.form_sec .form_input.err {
  border-bottom-color: #888;
}
.form_sec .cta_login {
  border: 1px solid #ec1940;
  border-radius: 2px;
  background-color: #ec1940;
  font-size: 14px;
  font-weight: 500;
  text-align: center;
  color: #ffffff;
  padding: 15px 40px;
  margin-top: 30px;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form class="form_sec">
    <div class="row clearfix">
        <div class="form-group col-lg-6 col-md-6 form_input_wrap">
            <label>
                Full Name
            </label>
            <input type="text" name="name" id="name" class="form_input js_modern_input">
        </div>
    </div>
    <div class="row clearfix">
        <div class="form-group form_input_wrap col-lg-6 col-md-6">
            <label>
                Emaill
            </label>
            <input type="email" name="email" class="form_input js_modern_input">
        </div>
    </div>
    <div class="row clearfix">
        <div class="form-group form_input_wrap col-lg-12 col-md-12">
            <label>
                Address Line 1
            </label>
            <input type="text" name="address" class="form_input js_modern_input">
        </div>
    </div>
    <div class="row clearfix">
        <div class="form-group col-lg-6 col-md-6 form_input_wrap">
            <label>
                City
            </label>
            <input type="text" name="city" class="form_input js_modern_input">
        </div>
        <div class="form-group col-lg-6 col-md-6 form_input_wrap">
            <label>
                State
            </label>
            <input type="text" name="state" class="form_input js_modern_input">
        </div>
    </div>
    <div class="row clearfix">
        <div class="form-group col-lg-6 col-md-6 form_input_wrap">
            <label>
                Country
            </label>
            <input type="text" name="country" class="form_input js_modern_input">
        </div>
        <div class="form-group col-lg-4 col-md-4 form_input_wrap">
            <label>
                Pin
            </label>
            <input type="text" name="pincode" class="form_input js_modern_input">
        </div>
    </div>
    <div class="row cta_sec">
        <div class="col-lg-12">
            <button type="submit" class="cta_login">Submit</button>
        </div>
    </div>
</form>

2
Suresh Pattu

J'ai utilisé cette solution pour le même problème.

Le code HTML devrait changer en ceci: 

<input type="text" name="username" />
<input type="text" name="password" id="txt_password" />

et le code jQuery doit être dans document.ready:

$('#txt_password').focus(function(){
    $(this).attr('type','password');
});
1
amir2h

Je sais que c'est un vieux fil, mais j'imagine que beaucoup viennent y trouver une solution.

Pour ce faire, vous pouvez vérifier si la ou les entrées ont une valeur avec:

$(function() {
    setTimeout(function() {
        if ($("#inputID").val().length > 0) {
            // YOUR CODE
        }
    }, 100);
});

J'utilise ceci moi-même pour vérifier les valeurs dans mon formulaire de connexion lorsqu'il est chargé pour activer le bouton d'envoi .. Le code est fait pour jQuery mais est facile à changer si nécessaire.

1
S.Lund

J'ai également rencontré le même problème: Label ne détectait pas de remplissage automatique et l'animation de déplacement d'étiquette lors du remplissage de texte se chevauchait et cette solution fonctionnait pour moi.

input:-webkit-autofill ~ label {
    top:-20px;
} 
1
st0495

J'ai eu le même problème et j'ai écrit cette solution.

Il lance la scrutation sur chaque champ de saisie lors du chargement de la page (je l’ai défini 10 secondes mais vous pouvez régler cette valeur).
Au bout de 10 secondes, il cesse de scruter tous les champs d’entrée et ne commence à scruter que sur l’entrée focalisée (le cas échéant) .

De cette manière, vous n'interrogez que lorsque cela est vraiment nécessaire et uniquement sur une entrée valide.

// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
    $("input").each(function() {
        if ($(this).val() !== $(this).attr("value")) {
            $(this).trigger("change");
        }
    });
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
    clearInterval(loading);
}, 10000);
// Now we just listen on the focused inputs (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
    var $this = $(this);
    focused = setInterval(function() {
        if ($this.val() !== $this.attr("value")) {
            $this.trigger("change");
        }
    }, 100);
})
.on("blur", "input", function() {
    clearInterval(focused);
});

Cela ne fonctionne pas très bien lorsque plusieurs valeurs sont insérées automatiquement, mais il peut être modifié en recherchant chaque entrée du formulaire actuel.

Quelque chose comme:

// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
    $("input").each(function() {
        if ($(this).val() !== $(this).attr("value")) {
            $(this).trigger("change");
        }
    });
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
    clearInterval(loading);
}, 10000);
// Now we just listen on inputs of the focused form
var focused;
$(document)
.on("focus", "input", function() {
    var $inputs = $(this).parents("form").find("input");
    focused = setInterval(function() {
        $inputs.each(function() {
            if ($(this).val() !== $(this).attr("value")) {
                $(this).trigger("change");
            }
        });
    }, 100);
})
.on("blur", "input", function() {
    clearInterval(focused);
});
0
Fez Vrasta

D'après mon expérience personnelle, le code ci-dessous fonctionne bien avec firefox IE et safari, mais ne fonctionne pas très bien pour la saisie automatique en chrome.

function check(){
clearTimeout(timeObj);
 timeObj = setTimeout(function(){
   if($('#email').val()){
    //do something
   }
 },1500);
}

$('#email').bind('focus change blur',function(){
 check();
});

Le code ci-dessous fonctionne mieux car il se déclenche chaque fois que l'utilisateur clique sur le champ de saisie et à partir de là, vous pouvez vérifier si le champ de saisie est vide ou non. 

$('#email').bind('click', function(){
 check();
});
0
roger

Ma solution est:

    $.fn.onAutoFillEvent = function (callback) {
        var el = $(this),
            lastText = "",
            maxCheckCount = 10,
            checkCount = 0;

        (function infunc() {
            var text = el.val();

            if (text != lastText) {
                lastText = text;
                callback(el);
            }
            if (checkCount > maxCheckCount) {
                return false;
            }
            checkCount++;
            setTimeout(infunc, 100);
        }());
    };

  $(".group > input").each(function (i, element) {
      var el = $(element);

      el.onAutoFillEvent(
          function () {
              el.addClass('used');
          }
      );
  });
0
Romick

Après des recherches, le problème est que les navigateurs Webkit ne déclenchent pas les événements de modification lors de la saisie semi-automatique. Ma solution consistait à obtenir la classe de remplissage automatique ajoutée par Webkit et à déclencher moi-même un événement de changement.

setTimeout(function() {
 if($('input:-webkit-autofill').length > 0) {
   //do some stuff
 }
},300)

Voici un lien pour la question en chrome. https://bugs.chromium.org/p/chromium/issues/detail?id=636425

0
Cvetan Himchev

Si vous souhaitez uniquement déterminer si le remplissage automatique a été utilisé ou non, plutôt que de déterminer exactement quand et à quel champ le remplissage automatique a été utilisé, vous pouvez simplement ajouter un élément masqué qui sera rempli automatiquement contient n'importe quelle valeur. Je comprends que cela pourrait ne pas intéresser de nombreuses personnes. Définissez le champ de saisie avec un tabIndex négatif et des coordonnées absolues bien à l’écran. Il est important que l'entrée fasse partie du même formulaire que le reste de l'entrée. Vous devez utiliser un nom qui sera récupéré par remplissage automatique (ex. "Secondname").

var autofilldetect = document.createElement('input');
autofilldetect.style.position = 'absolute';
autofilldetect.style.top = '-100em';
autofilldetect.style.left = '-100em';
autofilldetect.type = 'text';
autofilldetect.name = 'secondname';
autofilldetect.tabIndex = '-1';

Ajoutez cette entrée au formulaire et vérifiez sa valeur lors de la soumission du formulaire.

0
bornSwift

J'ai réussi le chrome avec:

    setTimeout(
       function(){
          $("#input_password").focus();
          $("#input_username").focus();
          console.log($("#input_username").val());
          console.log($("#input_password").val());
       }
    ,500);
0
Antoine O

J'ai utilisé l'événement blur sur le nom d'utilisateur pour vérifier si le champ pwd avait été rempli automatiquement.

 $('#userNameTextBox').blur(function () {
        if ($('#userNameTextBox').val() == "") {
            $('#userNameTextBox').val("User Name");
        }
        if ($('#passwordTextBox').val() != "") {
            $('#passwordTextBoxClear').hide(); // textbox with "Password" text in it
            $('#passwordTextBox').show();
        }
    });

Cela fonctionne pour IE et devrait fonctionner pour tous les autres navigateurs (j'ai seulement vérifié IE)

0
Bridget Arrington

Ceci est une solution pour les navigateurs avec moteur de rendu webkit . Lorsque le formulaire est rempli automatiquement, les entrées obtiendront une pseudo classe: -webkit-autofill- (exemple: -webkit-autofill {.. .}). C'est donc l'identifiant que vous devez vérifier via JavaScript.

Solution avec une forme de test:

<form action="#" method="POST" class="js-filled_check">

    <fieldset>

        <label for="test_username">Test username:</label>
        <input type="text" id="test_username" name="test_username" value="">

        <label for="test_password">Test password:</label>
        <input type="password" id="test_password" name="test_password" value="">

        <button type="submit" name="test_submit">Test submit</button>

    </fieldset>

</form>

Et javascript:

$(document).ready(function() {

    setTimeout(function() {

        $(".js-filled_check input:not([type=submit])").each(function (i, element) {

            var el = $(this),
                autofilled = (el.is("*:-webkit-autofill")) ? el.addClass('auto_filled') : false;

            console.log("element: " + el.attr("id") + " // " + "autofilled: " + (el.is("*:-webkit-autofill")));

        });

    }, 200);

});

Le problème lors du chargement de la page est d'obtenir la valeur du mot de passe, même sa longueur. C'est parce que la sécurité du navigateur. Aussi, le timeout , c'est parce que le navigateur remplira le formulaire après une séquence temporelle. 

Ce code ajoutera la classe auto_filled aux entrées remplies. En outre, j'ai essayé de vérifier la valeur ou la longueur du mot de passe du type d'entrée, mais cela a fonctionné juste après qu'un événement se soit produit sur la page. J'ai donc essayé de déclencher un événement, mais sans succès. Pour l'instant c'est ma solution . Profitez-en! 

0
Adam Šipický

Voici la solution CSS extraite de l’équipe de Klarna UI. Voir leur implémentation de Nice ici ressource

Fonctionne bien pour moi.

input:-webkit-autofill {
  animation-name: onAutoFillStart;
  transition: background-color 50000s ease-in-out 0s;
}
input:not(:-webkit-autofill) {
  animation-name: onAutoFillCancel;
}
0
zdrsoft

Il y a semble-t-il une solution à ce problème qui ne repose pas sur l'interrogation (du moins pour Chrome). C'est presque aussi bidon, mais je pense que c'est légèrement mieux que les sondages mondiaux.

Considérez le scénario suivant:

  1. L'utilisateur commence à remplir field1

  2. L'utilisateur sélectionne une suggestion de saisie semi-automatique qui remplit automatiquement les champs 2 et 3.

Solution: Enregistrez un onblur sur tous les champs pour vérifier la présence de champs remplis automatiquement via l'extrait de code jQuery $ (': - webkit-autofill').

Ce ne sera pas immédiat car il sera retardé jusqu'à ce que l'utilisateur floute field1, mais il ne repose pas sur une interrogation globale, alors IMO, c'est une meilleure solution.

Cela dit, comme il est possible de soumettre un formulaire en appuyant sur la touche Entrée, vous pouvez également avoir besoin d'un gestionnaire correspondant pour onkeypress.

Sinon, vous pouvez utiliser l'interrogation globale pour vérifier $ (': - webkit-autofill')

0
Dan D