Action de déclenchement sur la modification programmée à une valeur d'entrée

Mon objectif est d'observer une valeur d'entrée et de déclencher un gestionnaire lorsque sa valeur est modifiée par programmation . Je n'ai besoin que pour les navigateurs modernes.

J'ai essayé de nombreuses combinaisons en utilisant defineProperty et c'est ma dernière itération:

 var myInput=document.getElementById("myInput"); Object.defineProperty(myInput,"value",{ get:function(){ return this.getAttribute("value"); }, set:function(val){ console.log("set"); // handle value change here this.setAttribute("value",val); } }); myInput.value="new value"; // should trigger console.log and handler 

Cela semble faire ce que je m'attends, mais il se sent comme un hack car je dépasse la propriété de valeur existante et joue avec le double état de la value (attribut et propriété). Il brise également l'événement de change qui ne semble pas aimer la propriété modifiée.

Mes autres tentatives:

  • Une boucle setTimeout / setInterval, mais ce n'est pas propre non plus
  • watch et observe divers polyfills, mais ils se brisent pour une propriété de valeur d'entrée

Quel serait le bon moyen d'obtenir le même résultat?

Démo en direct: http://jsfiddle.net/L7Emx/4/

[Modifier] Pour clarifier: Mon code surveille un élément de saisie où d'autres applications peuvent pousser des mises à jour (à la suite d'appels ajax par exemple, ou à la suite de modifications dans d'autres champs). Je n'ai aucun contrôle sur la mise à jour des autres applications, je ne suis qu'un observateur.

[Modifier 2] Pour clarifier ce que je veux dire par «navigateur moderne», je serais très heureux d'une solution qui fonctionne sur IE 11 et Chrome 30.

[Mettre à jour] Démo mise à jour en fonction de la réponse acceptée: http://jsfiddle.net/L7Emx/10/

Le truc suggéré par @ mohit-jain est d'ajouter une deuxième entrée pour l'interaction de l'utilisateur.

Si le seul problème avec votre solution est la rupture de l'événement de changement sur la valeur définie. Vous pouvez déclencher cet événement manuellement sur l'ensemble. (Mais cela ne sera pas réglé si un utilisateur modifie l'entrée par navigateur – voir l' édition ci-dessous)

 <html> <body> <input type='hidden' id='myInput' /> <input type='text' id='myInputVisible' /> <input type='button' value='Test' onclick='return testSet();'/> <script> //hidden input which your API will be changing var myInput=document.getElementById("myInput"); //visible input for the users var myInputVisible=document.getElementById("myInputVisible"); //property mutation for hidden input Object.defineProperty(myInput,"value",{ get:function(){ return this.getAttribute("value"); }, set:function(val){ console.log("set"); //update value of myInputVisible on myInput set myInputVisible.value = val; // handle value change here this.setAttribute("value",val); //fire the event if ("createEvent" in document) { // Modern browsers var evt = document.createEvent("HTMLEvents"); evt.initEvent("change", true, false); myInput.dispatchEvent(evt); } else { // IE 8 and below var evt = document.createEventObject(); myInput.fireEvent("onchange", evt); } } }); //listen for visible input changes and update hidden myInputVisible.onchange = function(e){ myInput.value = myInputVisible.value; }; //this is whatever custom event handler you wish to use //it will catch both the programmatic changes (done on myInput directly) //and user's changes (done on myInputVisible) myInput.onchange = function(e){ console.log(myInput.value); }; //test method to demonstrate programmatic changes function testSet(){ myInput.value=Math.floor((Math.random()*100000)+1); } </script> </body> </html> 

Plus sur les événements de tir manuellement


EDIT :

Le problème avec le déclenchement manuel d'événement et l'approche mutator est que la propriété value ne changera pas lorsque l'utilisateur modifie la valeur du champ du navigateur. Le travail consiste à utiliser deux champs. Un caché avec lequel nous pouvons avoir une interaction programmée. Un autre est visible avec lequel l'utilisateur peut interagir. Après cette approche de considération est assez simple.

  1. Mutate la valeur de la propriété sur le champ d'entrée caché pour observer les changements et le manuel d'incendie sur l'événement de changement. Sur la valeur définie, modifie la valeur du champ visible pour donner une rétroaction aux utilisateurs.
  2. Sur le changement de valeur de champ visible mettre à jour la valeur cachée pour l'observateur.

Je n'ai besoin que pour les navigateurs modernes.

Quelle est la modernité que vous aimeriez aller? Ecma Script 7 (6 sera finalisé en décembre) pourrait contenir Object.observe . Cela vous permettra de créer des observables natifs. Et oui, vous pouvez l'exécuter! Comment?

Pour expérimenter cette fonctionnalité, vous devez activer le drapeau JavaScript Enable Experimental dans Chrome Canary et redémarrer le navigateur. Le drapeau peut être trouvé sous 'about:flags'

Plus d'infos: lisez ceci .

Donc oui, c'est très expérimental et pas prêt dans le jeu actuel de navigateurs. En outre, il n'est toujours pas entièrement prêt et pas 100% s'il arrive à ES7, et la date finale pour ES7 n'est pas encore définie. Pourtant, je voulais vous informer pour une utilisation future.

Comme vous utilisez déjà des polyfills pour regarder / observer, etc., permettez-moi de saisir l'occasion pour vous suggérer Angularjs .

Il offre exactement cette fonctionnalité sous la forme de ses ng-models. Vous pouvez mettre les observateurs sur la valeur du modèle, et quand cela change, vous pouvez alors appeler d'autres fonctions.

Voici une solution très simple mais fonctionnelle à ce que vous voulez:

http://jsfiddle.net/RedDevil/jv8pK/

Fondamentalement, faites une saisie de texte et liez-le à un modèle:

 <input type="text" data-ng-model="variable"> 

Puis mettez un observateur sur le modèle angularjs sur cette entrée dans le contrôleur.

 $scope.$watch(function() { return $scope.variable }, function(newVal, oldVal) { if(newVal !== null) { window.alert('programmatically changed'); } }); 

Il existe un moyen de le faire. Il n'y a pas d'événement DOM pour cela, mais il existe un événement javascript qui déclenche un changement de propriété d'objet.

 document.form1.textfield.watch("value", function(object, oldval, newval){}) ^ Object watched ^ ^ ^ |_ property watched | | |________|____ old and new value 

Dans le rappel, vous pouvez faire quoi que ce soit.


Dans cet exemple, nous pouvons voir cet effet (Vérifiez jsFiddle ):

 var obj = { prop: 123 }; obj.watch('prop', function(propertyName, oldValue, newValue){ console.log('Old value is '+oldValue); // 123 console.log('New value is '+newValue); // 456 }); obj.prop = 456; 

Lorsque obj change, il active l'auditeur de watch .

Vous avez plus d'informations sur ce lien: http://james.padolsey.com/javascript/monitoring-dom-properties/

J'ai écrit le Gist suivant il y a quelque temps, ce qui permet d'écouter des événements personnalisés sur le navigateur croisé (y compris IE8 +).

Jetez un oeil à la façon dont onpropertychange sur IE8.

 util.listenToCustomEvents = function (event_name, callback) { if (document.addEventListener) { document.addEventListener(event_name, callback, false); } else { document.documentElement.attachEvent('onpropertychange', function (e) { if(e.propertyName == event_name) { callback(); } } }; 

Je ne suis pas sûr que la solution IE8 fonctionne avec un navigateur croisé, mais vous pouvez configurer un faux eventlistener d' eventlistener sur la value de votre entrée et exécuter un rappel une fois que la valeur des changements de value déclenchée par onpropertychange .