web-dev-qa-db-fra.com

Détecte toutes les modifications apportées à <input type = "text"> (immédiatement) à l'aide de JQuery

La valeur d'un <input type="text"> peut changer de plusieurs manières, notamment:

  • touches
  • copier coller
  • modifié avec JavaScript
  • rempli automatiquement par le navigateur ou une barre d'outils

Je souhaite que ma fonction JavaScript soit appelée (avec la valeur d'entrée actuelle) chaque fois qu'elle change. Et je veux qu'il soit appelé immédiatement, pas seulement lorsque l'entrée perd le focus.

Je cherche le moyen le plus propre et le plus robuste de le faire sur tous les navigateurs (en utilisant de préférence jQuery).

Exemple de cas d'utilisation: Sur la page Twitter Signup , la valeur du champ nom d'utilisateur est indiquée dans l'URL " http : // Twitter / nom d'utilisateur "en dessous.

379
Dustin Boswell

Malheureusement, je pense que setInterval gagne le prix:

<input type=text id=input_id />
<script>
setInterval(function() { ObserveInputValue($('#input_id').val()); }, 100);
</script>

C'est la solution la plus propre, avec une seule ligne de code. C'est aussi le plus robuste, car vous n'avez pas à vous soucier de tous les événements/façons dont une input peut obtenir une valeur.

Les inconvénients de l'utilisation de 'setInterval' ne semblent pas s'appliquer dans ce cas:

  • La latence de 100ms? Pour de nombreuses applications, 100ms est assez rapide.
  • Ajout de la charge sur le navigateur? En général, ajouter beaucoup de poids lourds setIntervals sur votre page est mauvais. Mais dans ce cas particulier, le chargement de page ajouté est indétectable.
  • Il ne s’adapte pas à beaucoup d’entrées? La plupart des pages n’ont pas plus d’une poignée d’entrées, que vous pouvez renifler dans le même setInterval.
102
Dustin Boswell

Ce code jQuery capture les modifications immédiates de tout élément et devrait fonctionner sur tous les navigateurs:

 $('.myElements').each(function() {
   var elem = $(this);

   // Save current value of element
   elem.data('oldVal', elem.val());

   // Look for changes in the value
   elem.bind("propertychange change click keyup input paste", function(event){
      // If value has changed...
      if (elem.data('oldVal') != elem.val()) {
       // Updated stored value
       elem.data('oldVal', elem.val());

       // Do action
       ....
     }
   });
 });
337
phatmann

Une solution de fantaisie en temps réel pour jQuery> = 1.9

$("#input-id").on("change keyup paste", function(){
    dosomething();
})

si vous souhaitez également détecter un événement "clic", il suffit de:

$("#input-id").on("change keyup paste click", function(){
    dosomething();
})

si vous utilisez jQuery <= 1.4, utilisez simplement live au lieu de on.

120
Felix

La liaison à l'événement oninput semble fonctionner correctement dans la plupart des navigateurs rationnels. IE9 le prend également en charge, mais son implémentation est erronée (l'événement n'est pas déclenché lors de la suppression de caractères).

Avec jQuery version 1.7+, la méthode on est utile pour se lier à l'événement de la manière suivante:

$(".inputElement").on("input", null, null, callbackFunction);
57
HRJ

2017 réponse : le événement d'entrée fait exactement cela pour tout ce qui est plus récent que IE8.

$(el).on('input', callback)
28
Chris F Carroll

Malheureusement, aucun événement ou ensemble d'événements ne correspond à vos critères. Les touches et les copier/coller peuvent être gérés avec l'événement keyup. Les changements via JS sont plus compliqués. Si vous avez le contrôle sur le code qui définit la zone de texte, le mieux est de le modifier pour appeler directement votre fonction ou déclencher un événement utilisateur sur la zone de texte:

// Compare the textbox's current and last value.  Report a change to the console.
function watchTextbox() {
  var txtInput = $('#txtInput');
  var lastValue = txtInput.data('lastValue');
  var currentValue = txtInput.val();
  if (lastValue != currentValue) {
    console.log('Value changed from ' + lastValue + ' to ' + currentValue);
    txtInput.data('lastValue', currentValue);
  }
}

// Record the initial value of the textbox.
$('#txtInput').data('lastValue', $('#txtInput').val());

// Bind to the keypress and user-defined set event.
$('#txtInput').bind('keypress set', null, watchTextbox);

// Example of JS code triggering the user event
$('#btnSetText').click(function (ev) {
  $('#txtInput').val('abc def').trigger('set');
});

Si vous n'avez pas le contrôle sur ce code, vous pouvez utiliser setInterval() pour "surveiller" la zone de texte afin de détecter les modifications:

// Check the textbox every 100 milliseconds.  This seems to be pretty responsive.
setInterval(watchTextbox, 100);

Ce type de surveillance active ne détectera pas les mises à jour "immédiatement", mais il semble être assez rapide pour qu'il n'y ait pas de décalage perceptible. Comme DrLouie l'a souligné dans ses commentaires, cette solution ne fonctionne probablement pas bien si vous devez surveiller de nombreuses entrées. Vous pouvez toujours régler le deuxième paramètre sur setInterval() pour vérifier plus ou moins fréquemment.

15
Annabelle

Voici une solution légèrement différente si vous n'avez pas envie d'une autre réponse:

var field_selectors = ["#a", "#b"];
setInterval(function() { 
  $.each(field_selectors, function() { 
    var input = $(this);
    var old = input.attr("data-old-value");
    var current = input.val();
    if (old !== current) { 
      if (typeof old != 'undefined') { 
        ... your code ...
      }
      input.attr("data-old-value", current);
    }   
  }   
}, 500);

Considérez que vous ne pouvez pas compter sur click et keyup pour capturer le collage du menu contextuel.

6
Peder

Ajoutez ce code quelque part, cela fera l'affaire.

var originalVal = $.fn.val;
$.fn.val = function(){
    var result =originalVal.apply(this,arguments);
    if(arguments.length>0)
        $(this).change(); // OR with custom event $(this).trigger('value-changed');
    return result;
};

Trouvé cette solution à val () ne déclenche pas change () dans jQuery

4
lpradhap

En réalité, nous n'avons pas besoin de configurer des boucles pour détecter les modifications JavaScript. Nous avons déjà configuré de nombreux écouteurs d’événements pour l’élément que nous voulons détecter. le simple fait de déclencher un événement néfaste fera le travail.

$("input[name='test-element']").on("propertychange change click keyup input paste blur", function(){
console.log("yeh thats worked!");
});

$("input[name='test-element']").val("test").trigger("blur");

et ofc, ceci n’est disponible que si vous avez le contrôle total sur les modifications de javascript de votre projet.

3
Serdar

J'ai créé un échantillon. Puisse cela fonctionner pour vous.

var typingTimer;
var doneTypingInterval = 10;
var finaldoneTypingInterval = 500;

var oldData = $("p.content").html();
$('#tyingBox').keydown(function () {
    clearTimeout(typingTimer);
    if ($('#tyingBox').val) {
        typingTimer = setTimeout(function () {
            $("p.content").html('Typing...');
        }, doneTypingInterval);
    }
});

$('#tyingBox').keyup(function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function () {
        $("p.content").html(oldData);
    }, finaldoneTypingInterval);
});


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>


<textarea id="tyingBox" tabindex="1" placeholder="Enter Message"></textarea>
<p class="content">Text will be replace here and after Stop typing it will get back</p>

http://jsfiddle.net/utbh575s/

3
Ambuj Khanna

Eh bien, le meilleur moyen est de couvrir ces trois bases que vous avez énumérées par vous-même. Un simple: onblur, onkeyup, etc. ne fonctionnera pas comme vous le souhaitez, combinez-les simplement.

KeyUp devrait couvrir les deux premiers, et si Javascript est en train de modifier la zone de saisie, j'espère que c'est votre propre javascript, ajoutez donc un rappel dans la fonction qui le modifie.

1
idrumgood

Voici un exemple de travail que j'utilise pour implémenter une variante de complétion automatique: elle remplit un sélecteur jqueryui (liste), mais je ne souhaite pas qu'elle fonctionne exactement comme la saisie automatique jqueryui, qui comporte un menu déroulant.

$("#tagFilter").on("change keyup paste", function() {
     var filterText = $("#tagFilter").val();
    $("#tags").empty();
    $.getJSON("http://localhost/cgi-bin/tags.php?term=" + filterText,
        function(data) {
            var i;
            for (i = 0; i < data.length; i++) {
                var tag = data[i].value;
                $("#tags").append("<li class=\"tag\">" + tag + "</li>");
            }
        }); 
});
1
clearlight

Ne pouvez-vous pas simplement utiliser l'élément <span contenteditable="true" spellcheck="false"> à la place de <input type="text">?

<span> (avec contenteditable="true" spellcheck="false" comme attributs) se distingue par <input> principalement parce que:

  • Ce n'est pas comme un <input>.
  • Il n'a pas de propriété value, mais le texte est rendu sous la forme innerText et fait partie de son corps intérieur.
  • Il est multiligne alors que <input> ne l’est pas bien que vous ayez défini l’attribut multiline="true".

Pour obtenir l'apparence voulue, vous pouvez bien sûr la styler en CSS, alors que l'écriture de la valeur sous la forme innerText vous permet d'obtenir un événement:

Voici un violon .

Malheureusement, il y a quelque chose qui ne fonctionne pas dans IE et Edge, que je ne parviens pas à trouver.

0
Davide Cannizzo