texto style net modificar con change cambiar attribute asp javascript html-input defineproperty

javascript - style - title css



Acción de disparo en el cambio programático a un valor de entrada (6)

Mi objetivo es observar un valor de entrada y desencadenar un controlador cuando su valor se modifica mediante programación . Solo lo necesito para navegadores modernos.

He probado muchas combinaciones usando defineProperty y esta es mi última iteración:

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

Esto parece hacer lo que espero, pero se siente como un truco ya que estoy anulando la propiedad de valor existente y jugando con el estado dual del value (atributo y propiedad). También rompe el evento de change que no parece gustar la propiedad modificada.

Mis otros intentos:

  • un bucle setTimeout / setInterval, pero esto tampoco está limpio
  • varios watch y observe polifills, pero se rompen para una propiedad de valor de entrada

¿Cuál sería una forma adecuada de lograr el mismo resultado?

Demostración en vivo: http://jsfiddle.net/L7Emx/4/

[Editar] Para aclarar: Mi código está viendo un elemento de entrada donde otras aplicaciones pueden enviar actualizaciones (como resultado de llamadas ajax, por ejemplo, o como resultado de cambios en otros campos). No tengo control sobre cómo las otras aplicaciones envían actualizaciones, solo soy un observador.

[Editar 2] Para aclarar lo que quiero decir con "navegador moderno", me encantaría con una solución que funciona en IE 11 y Chrome 30.

[Actualización] Demo actualizada basada en la respuesta aceptada: http://jsfiddle.net/L7Emx/10/

El truco sugerido por @ mohit-jain es agregar una segunda entrada para la interacción del usuario.


Solo lo necesito para navegadores modernos.

¿Qué tan moderno te gustaría ir? Ecma Script 7 (6 se hará definitivo en diciembre) puede contener Object.observe . Esto le permitiría crear observables nativos. Y sí, puedes correrlo! ¿Cómo?

Para experimentar con esta función, debe habilitar el indicador Habilitar JavaScript experimental en Chrome Canary y reiniciar el navegador. La bandera se puede encontrar en ''about:flags''

Más información: lee esto .

Así que sí, esto es altamente experimental y no está listo en el conjunto actual de navegadores. Además, aún no está completamente listo y no está al 100% si llega a ES7, y la fecha final de ES7 aún no está establecida. Aún así, quería hacerle saber para uso futuro.


Escribí el siguiente Gist un rato, que permite escuchar eventos personalizados en todos los navegadores (incluido IE8 +).

Eche un vistazo a cómo escucho onpropertychange en 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(); } } };

No estoy seguro de que la solución IE8 funcione en todos los navegadores, pero podría establecer un eventlistener de eventlistener falso en el value de propiedad de su entrada y ejecutar una devolución de llamada una vez que el valor de los cambios de value desencadenados por onpropertychange .


Lo siguiente funciona en todos los lugares en los que lo he probado, incluido IE11 (incluso en el modo de emulación IE9).

Lleva su idea defineProperty un poco más allá al encontrar el objeto en la cadena de prototipos del elemento de entrada que define el establecedor de .value y al modificar este configurador para desencadenar un evento (lo he llamado modified en el ejemplo), mientras se mantiene el comportamiento anterior .

Cuando ejecute el fragmento de código a continuación, puede escribir / pegar / lo que sea en el cuadro de entrada de texto, o puede hacer clic en el botón que agrega " more" al valor .value del elemento de .value . En cualquier caso, el contenido de <span> se actualiza sincrónicamente.

Lo único que no se maneja aquí es una actualización causada por la configuración del atributo. Si lo desea, puede manejar eso con un MutationObserver , pero tenga en cuenta que no existe una relación de uno a uno entre .value y el atributo de value (este último es solo el valor predeterminado para el primero).

// make all input elements trigger an event when programmatically setting .value monkeyPatchAllTheThings(); var input = document.querySelector("input"); var span = document.querySelector("span"); function updateSpan() { span.textContent = input.value; } // handle user-initiated changes to the value input.addEventListener("input", updateSpan); // handle programmatic changes to the value input.addEventListener("modified", updateSpan); // handle initial content updateSpan(); document.querySelector("button").addEventListener("click", function () { input.value += " more"; }); function monkeyPatchAllTheThings() { // create an input element var inp = document.createElement("input"); // walk up its prototype chain until we find the object on which .value is defined var valuePropObj = Object.getPrototypeOf(inp); var descriptor; while (valuePropObj && !descriptor) { descriptor = Object.getOwnPropertyDescriptor(valuePropObj, "value"); if (!descriptor) valuePropObj = Object.getPrototypeOf(valuePropObj); } if (!descriptor) { console.log("couldn''t find .value anywhere in the prototype chain :("); } else { console.log(".value descriptor found on", "" + valuePropObj); } // remember the original .value setter ... var oldSetter = descriptor.set; // ... and replace it with a new one that a) calls the original, // and b) triggers a custom event descriptor.set = function () { oldSetter.apply(this, arguments); // for simplicity I''m using the old IE-compatible way of creating events var evt = document.createEvent("Event"); evt.initEvent("modified", true, true); this.dispatchEvent(evt); }; // re-apply the modified descriptor Object.defineProperty(valuePropObj, "value", descriptor); }

<input><br><br> The input contains "<span></span>"<br><br> <button>update input programmatically</button>


Puesto que ya está utilizando polyfills para ver / observar, etc., permítame aprovechar la oportunidad para sugerirle Angularjs .

Ofrece exactamente esta funcionalidad en forma de sus modelos ng. Puede poner a los observadores en el valor del modelo, y cuando cambie, puede llamar a otras funciones.

Aquí está una solución muy simple, pero de trabajo para lo que quieres:

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

Básicamente, haz una entrada de texto y vincúlala a un modelo:

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

luego coloque un observador en el modelo angularjs en esta entrada en el controlador.

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


hay una forma de hacer esto. No hay un evento DOM para esto, sin embargo, hay un evento javascript que se activa en un cambio de propiedad del objeto.

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

En el callback puedes hacer lo que sea.

En este ejemplo, podemos ver este efecto (verifique el 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;

Cuando se cambia de obj , se activa la escucha del watch .

Tiene más información en este enlace: http://james.padolsey.com/javascript/monitoring-dom-properties/


si el único problema con su solución es romper el evento de cambio en el valor establecido. entonces puedes disparar ese evento manualmente en el set. (Pero este monitor no se configura en caso de que un usuario realice un cambio en la entrada a través del navegador; consulte la edición a continuación)

<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>

más sobre disparar eventos manualmente

EDITAR :

El problema con la activación manual de eventos y el enfoque del mutador es que la propiedad de valor no cambiará cuando el usuario cambie el valor de campo desde el navegador. el trabajo alrededor es utilizar dos campos. Una oculta con la que podemos tener interacción programática. Otra es visible con la que el usuario puede interactuar. Después de este enfoque de consideración es bastante simple.

  1. mutar la propiedad de valor en el campo de entrada oculto para observar los cambios y disparar el evento de cambio manual. en el valor establecido, cambie el valor del campo visible para dar retroalimentación al usuario.
  2. en el cambio de valor del campo visible actualice el valor de oculto para el observador.