Comment détecter le contenu d'une zone de texte a changé

417

Je veux détecter chaque fois que le contenu d'une zone de texte a changé. Je peux utiliser la méthode des touches, mais cela détectera également les frappes qui ne génèrent pas de lettres, comme les touches fléchées. J'ai pensé à deux méthodes pour ce faire en utilisant l'événement keyup:

  1. Vérifiez explicitement si le code ascii de la touche enfoncée est une lettre \ backspace \ delete
  2. Utilisez les fermetures pour vous rappeler quel était le texte dans la zone de texte avant le coup de clé et vérifiez si cela a changé.

Les deux semblent un peu encombrants.

olamundo
la source
7
Oui, attraper le keyup pour cela est mauvais. Vous pouvez coller des éléments sans aucune pression sur une touche.
dépensé le
2
avez-vous des chances de publier votre solution finale? Je dois aussi résoudre ce problème :)
Matt Dotson
1
ou .keyup()événement ... plus d'informations ici: stackoverflow.com/questions/3003879/…
Victor S
1
Voir $ ("# some-input"). ChangePolling () ; pour un wrapper qui vérifie la valeur actuelle et déclenche .change()si elle a changé.
Joel Purra
vous devez également vérifier cela stackoverflow.com/a/23266812/3160597
azerafati

Réponses:

714

Commencez à observer l'événement «entrée» au lieu de «changer».

jQuery('#some_text_box').on('input', function() {
    // do your stuff
});

... qui est agréable et propre, mais peut être étendu à:

jQuery('#some_text_box').on('input propertychange paste', function() {
    // do your stuff
});
Atul Vani
la source
12
«live» est déconseillé. alors utilisez «on» stackoverflow.com/a/15111970/1724777
NavaRajan
21
Le seul inconvénient de 'input' est qu'il n'est pas compatible avec IE <9.
Catfish
5
l'entrée est un événement html5 qui n'est pas pris en charge dans tous les navigateurs. developer.mozilla.org/en-US/docs/Web/API/window.oninput
commonpike
18
Vous pouvez également couvrir plus de bases en utilisant: .on ('input propertychange paste', function () {
Graeck
23
Le seul inconvénient d'IE <9 est que personne ne l'utilise!
sohaiby
67

Utilisez l'événement onchange en HTML / JavaScript standard.

Dans jQuery, c'est l' événement change () . Par exemple:

$('element').change(function() { // do something } );

ÉDITER

Après avoir lu quelques commentaires, qu'en est-il:

$(function() {
    var content = $('#myContent').val();

    $('#myContent').keyup(function() { 
        if ($('#myContent').val() != content) {
            content = $('#myContent').val();
            alert('Content has been changed');
        }
    });
});
Waleed Amjad
la source
3
Oui, c'est similaire à ce que j'ai suggéré dans l'option # 2 dans ma question. Je préfère les fermetures car l'utilisation d'un global rendra cette fonction opérationnelle pour une seule zone de texte. Quoi qu'il en soit, il semble que jquery étrange n'ait pas une manière plus simple de le faire.
olamundo
1
C'est en effet bizarre, mais je doute qu'il existe une meilleure façon de le faire. Vous pouvez utiliser setInterval, puis vérifier si le contenu a été modifié toutes les 0,1 s, puis faire quelque chose. Cela inclura également les pâtes de souris, etc. Mais ça n'a pas l'air trop élégant.
Waleed Amjad, le
4
Il est toujours possible que le contenu puisse être modifié sans frappe, par exemple en collant avec la souris. Si vous vous souciez de cela, vous pourriez théoriquement attraper des événements de souris aussi, mais cette configuration est encore plus laide. D'un autre côté, si vous êtes prêt à ignorer les changements entraînés par la souris, cela suffira.
Adam Bellaire
45

L'événement «change» ne fonctionne pas correctement, mais l '«entrée» est parfaite.

$('#your_textbox').bind('input', function() {
    /* This will be fired every time, when textbox's value changes. */
} );
schwarzkopfb
la source
7
Cela fonctionne parfaitement pour ma situation, bien que l'utilisation de .onsoit recommandée à partir de 1.7 (plutôt que .bind).
Nick
8
OP n'a pas précisé le besoin de compatibilité entre navigateurs. @schwarzkopfb a fourni une solution. Aucune raison de voter parce que vous avez le représentant pour le faire.
David East
3
@David, il n'a pas non plus précisé quel navigateur
ozz
9
@ jmo21 Je pense que nous pouvons supposer que pour le développement web, quand un navigateur n'est pas spécifique, la solution doit être interfonctionnelle. La norme prend en charge tous les navigateurs.
Chris
3
@Chris "La norme prend en charge tous les navigateurs" - uniquement si vous êtes sadique. Il n'y a aucune bonne raison d'éviter la bonté HTML5 pour les 2% d'utilisateurs mondiaux sur IE 8/9. caniuse.com/#feat=input-event
Yarin
39

Que dis-tu de ça:

<jQuery 1.7

$("#input").bind("propertychange change keyup paste input", function(){
    // do stuff;
});

> jQuery 1.7

$("#input").on("propertychange change keyup paste input", function(){
    // do stuff;
});

Cela fonctionne dans IE8 / IE9, FF, Chrome

Poisson-chat
la source
1
Le problème que j'ai avec cette réponse est qu'elle se déclenche une fois que vous avez brouillé la zone de texte, même si la valeur n'a pas changé. Le coupable est le "changement".
Justin
Utilisez-vous Chrome? Il semble que ce soit un bug avec Chrome et non l'événement de changement de jQuery bugs.jquery.com/ticket/9335
Catfish
fonctionne mais a un bug mineur si vous effectuez console.logla valeur du champ qu'il enregistre deux fois chaque fois que vous entrez un caractère.
Samuel M.
21

Utilisez les fermetures pour vous rappeler quel était le texte dans la case à cocher avant le coup de clé et vérifiez si cela a changé.

Oui. Vous n'avez pas besoin d'utiliser nécessairement des fermetures, mais vous devrez vous souvenir de l'ancienne valeur et la comparer à la nouvelle.

Toutefois! Cela n'attrapera toujours pas tous les changements, car il existe des moyens de modifier le contenu de la zone de texte qui n'impliquent aucune pression sur une touche. Par exemple, sélectionner une plage de texte, puis cliquer avec le bouton droit de la souris. Ou en le faisant glisser. Ou déposez du texte d'une autre application dans la zone de texte. Ou changer un mot via la vérification orthographique du navigateur. Ou...

Donc, si vous devez détecter chaque changement, vous devez l'interroger. Vous pouvez window.setIntervalvérifier le champ par rapport à sa valeur précédente toutes les (disons) secondes. Vous pouvez également câbler onkeyupà la même fonction afin que les changements qui sont causés par des frappes de touches se reflètent plus rapidement.

Lourd? Oui. Mais c'est ça ou faites-le simplement de la manière habituelle de changement HTML et n'essayez pas de mettre à jour instantanément.

bobince
la source
1
De nos jours, l' inputévénement HTML5 est viable et fonctionne dans les versions actuelles de tous les principaux navigateurs.
Tim Down du
13
$(document).on('input','#mytxtBox',function () { 
 console.log($('#mytxtBox').val());
});

Vous pouvez utiliser l'événement 'input' pour détecter le changement de contenu dans la zone de texte. N'utilisez pas «live» pour lier l'événement car il est obsolète dans Jquery-1.7, alors utilisez «on».

NavaRajan
la source
@NavaRajan Je viens de le tester à nouveau dans IE9. ne fonctionne vraiment pas sur le retour arrière.
Flores
Je ne veux PAS utiliser .live, mais le problème que j'ai est que je suis en quelque sorte retourné "vers le futur" et sur un projet mvc3 dans lequel le chef d'équipe veut s'en tenir à "out of the box" donc pas seulement EF 4.0, mais jquery 1.5.1 est utilisé ALORS .on () n'était pas dans 1.5.1, car il a été ajouté dans la version 1.7 de jquery api.jquery.com/on
Tom Stickel
5

Je suppose que vous cherchez à faire quelque chose d'interactif lorsque la zone de texte change (c'est-à-dire récupérer des données via ajax). Je cherchais cette même fonctionnalité. Je sais que l'utilisation d'une solution globale n'est pas la solution la plus robuste ou élégante, mais c'est ce que j'ai choisi. Voici un exemple:

var searchValue = $('#Search').val();
$(function () {
    setTimeout(checkSearchChanged, 0.1);
});

function checkSearchChanged() {
    var currentValue = $('#Search').val();
    if ((currentValue) && currentValue != searchValue && currentValue != '') {
        searchValue = $('#Search').val();
        $('#submit').click();
    }
    else {
        setTimeout(checkSearchChanged, 0.1);
    }
}

Une chose clé à noter ici est que j'utilise setTimeout et non setInterval car je ne veux pas envoyer plusieurs demandes en même temps. Cela garantit que la minuterie "s'arrête" lorsque le formulaire est soumis et "démarre" lorsque la demande est terminée. Je le fais en appelant checkSearchChanged à la fin de mon appel ajax. Évidemment, vous pouvez l'étendre pour vérifier la longueur minimale, etc.

Dans mon cas, j'utilise ASP.Net MVC afin que vous puissiez voir comment lier cela à MVC Ajax également dans l'article suivant:

http://geekswithblogs.net/DougLampe/archive/2010/12/21/simple-interactive-search-with-jquery-and-asp.net-mvc.aspx

Doug Lampe
la source
4

Je recommanderais de jeter un œil au widget de saisie semi-automatique de jQuery UI. Ils ont traité la plupart des cas là-bas, car leur base de code est plus mature que la plupart des autres.

Vous trouverez ci-dessous un lien vers une page de démonstration afin que vous puissiez vérifier que cela fonctionne. http://jqueryui.com/demos/autocomplete/#default

Vous obtiendrez le plus d'avantages en lisant la source et en voyant comment ils l'ont résolu. Vous pouvez le trouver ici: https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.autocomplete.js .

Fondamentalement, ils font tout, ils se lient à input, keydown, keyup, keypress, focus and blur. Ensuite, ils ont un traitement spécial pour toutes sortes de clés comme page up, page down, up arrow key and down arrow key. Une minuterie est utilisée avant d'obtenir le contenu de la zone de texte. Lorsqu'un utilisateur tape une clé qui ne correspond pas à une commande (touche haut, touche bas, etc.), un temporisateur explore le contenu après environ 300 millisecondes. Cela ressemble à ceci dans le code:

// switch statement in the 
switch( event.keyCode ) {
            //...
            case keyCode.ENTER:
            case keyCode.NUMPAD_ENTER:
                // when menu is open and has focus
                if ( this.menu.active ) {
                    // #6055 - Opera still allows the keypress to occur
                    // which causes forms to submit
                    suppressKeyPress = true;
                    event.preventDefault();
                    this.menu.select( event );
                }
                break;
            default:
                suppressKeyPressRepeat = true;
                // search timeout should be triggered before the input value is changed
                this._searchTimeout( event );
                break;
            }
// ...
// ...
_searchTimeout: function( event ) {
    clearTimeout( this.searching );
    this.searching = this._delay(function() { // * essentially a warpper for a setTimeout call *
        // only search if the value has changed
        if ( this.term !== this._value() ) { // * _value is a wrapper to get the value *
            this.selectedItem = null;
            this.search( null, event );
        }
    }, this.options.delay );
},

La raison d'utiliser un minuteur est pour que l'interface utilisateur ait une chance d'être mise à jour. Lorsque Javascript est en cours d'exécution, l'interface utilisateur ne peut pas être mise à jour, donc l'appel à la fonction de retard. Cela fonctionne bien pour d'autres situations telles que garder le focus sur la zone de texte (utilisée par ce code).

Vous pouvez donc utiliser le widget ou copier le code dans votre propre widget si vous n'utilisez pas jQuery UI (ou dans mon cas, développer un widget personnalisé).

Michael Yagudaev
la source
2

Je voudrais vous demander pourquoi vous essayez de détecter quand le contenu de la zone de texte a changé en temps réel ?

Une alternative serait de définir une minuterie (via setIntval?) Et de comparer la dernière valeur enregistrée à la valeur actuelle, puis de réinitialiser une minuterie. Cela garantirait la capture de N'IMPORTE QUEL changement, qu'il soit causé par les touches, la souris, un autre périphérique d'entrée que vous n'avez pas considéré, ou même que JavaScript change la valeur (une autre possibilité que personne n'a mentionnée) à partir d'une autre partie de l'application.

DVK
la source
ma situation (qui m'a amené à cette question) est que je dois afficher un bouton «Mettre à jour le panier» lorsque la quantité dans une zone de texte est modifiée. l'utilisateur n'a aucune idée qu'il doit perdre le focus et peut ne pas voir le bouton.
Simon_Weaver
Désolé, je ne suis pas sûr que cela réponde à la question «pourquoi ne pas vérifier les différences sur un calendrier». Vérifiez juste assez souvent (tous les 1/4 de seconde) et l'utilisateur ne verra aucune différence.
DVK
1

envisagez-vous d'utiliser l' événement de changement ?

$("#myTextBox").change(function() { alert("content changed"); });
Canavar
la source
5
AFAIK, il n'est déclenché que lorsque le focus de l'élément est perdu. Quelqu'un qui connaît les fermetures connaît probablement celui-ci. :)
simon
oui, cela ne fonctionnera pas - l'événement change n'est appelé que lorsque la zone de texte perd le focus. Je veux gérer le changement juste après avoir appuyé sur la touche.
olamundo
1

Utilisez l' textchangeévénement via un module d'interface jQuery personnalisé pour la inputcompatibilité entre les navigateurs . http://benalpert.com/2013/06/18/a-near-perfect-oninput-shim-for-ie-8-and-9.html (dernier github bifurqué: https://github.com/pandell /jquery-splendid-textchange/blob/master/jquery.splendid.textchange.js )

Ce gère toutes les balises d'entrée , y compris <textarea>content</textarea>, ce qui ne fonctionne pas toujours , change keyupetc. (!) Seulement jQuery on("input propertychange")poignées <textarea>balises de manière cohérente, et ce qui précède est une cale pour tous les navigateurs qui ne comprennent pas l' inputévénement.

<!DOCTYPE html>
<html>
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://raw.githubusercontent.com/pandell/jquery-splendid-textchange/master/jquery.splendid.textchange.js"></script>
<meta charset=utf-8 />
<title>splendid textchange test</title>

<script> // this is all you have to do. using splendid.textchange.js

$('textarea').on("textchange",function(){ 
  yourFunctionHere($(this).val());    });  

</script>
</head>
<body>
  <textarea style="height:3em;width:90%"></textarea>
</body>
</html>

Test JS Bin

Cela gère également le collage, la suppression et ne fait pas double emploi avec les touches.

Si vous n'utilisez pas de shim, utilisez les on("input propertychange")événements jQuery .

// works with most recent browsers (use this if not using src="...splendid.textchange.js")

$('textarea').on("input propertychange",function(){ 
  yourFunctionHere($(this).val());    
});  
Ber
la source
0

Il y a un exemple de travail complet ici .

<html>
<title>jQuery Summing</title>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> </script>
$(document).ready(function() {
$('.calc').on('input', function() {
var t1 = document.getElementById('txt1');
var t2 = document.getElementById('txt2');
var tot=0;
if (parseInt(t1.value))
tot += parseInt(t1.value);
if (parseInt(t2.value))
tot += parseInt(t2.value);
document.getElementById('txt3').value = tot;
});
});
</script>
</head>
<body>
<input type='text' class='calc' id='txt1'>
<input type='text' class='calc' id='txt2'>
<input type='text' id='txt3' readonly>
</body>
</html>
worldofjr
la source
0

Quelque chose comme ça devrait fonctionner, principalement parce que focuset focusoutse retrouverait avec deux valeurs distinctes. J'utilise dataici car il stocke des valeurs dans l'élément mais ne touche pas le DOM. C'est aussi un moyen simple de stocker la valeur connectée à son élément. Vous pouvez tout aussi facilement utiliser une variable de portée supérieure.

var changed = false;

$('textbox').on('focus', function(e) {
    $(this).data('current-val', $(this).text();
});

$('textbox').on('focusout', function(e) {
    if ($(this).data('current-val') != $(this).text())
        changed = true;
    }
    console.log('Changed Result', changed);
}
smcjones
la source
0

Ce code détecte chaque fois que le contenu d'une zone de texte a changé par l'utilisateur et modifié par le code Javascript.

var $myText = jQuery("#textbox");

$myText.data("value", $myText.val());

setInterval(function() {
    var data = $myText.data("value"),
    val = $myText.val();

    if (data !== val) {
        console.log("changed");
        $myText.data("value", val);
    }
}, 100);
Sandeep Yadav
la source