Reputation: 12532
I need a way to identify a property of an object (of type DOMNode) has undergone a change (or was created or removed, optionally).
I have an INPUT element and must be notified when the property .value
is modified. The problem is that not there is an attr definition, which I could use MutationObserver, and yes, a property definition (input.value
) and it not trigger the observer.
I can use the latest features available, since I will not use IE (bwhahahah).
Edit #1
I make this test to show:
__defineSetter__
works very fine, except that I can't use it without stop the "default propagation".If there is any way to allow the __defineSetter__
to continue until the end, would solve the case.
Upvotes: 1
Views: 199
Reputation: 707228
You don't really say whether you're only trying to track user changes to the input element or also programmatic changes. For newish browsers, you can monitor the input
event and it will tell you when the value of the input field has been changed by user control. There is no cross browser way to tell if the value of a field has been changed programmatically other than hooking all code that might change it to add your own notification system that a change may have been applied.
I wrote this cross browser function awhile ago to monitor all various forms of user change to an input field across all browsers. This code happens to be in the form of a jQuery method, but the logic could be modified to be plain javascript fairly easily. This code checks to see if the newish events are supported. If so, it uses them. If not, it hooks a lot of other events to try to trap all the possible ways the user could change the field (drag/drop, copy/paste, typing, etc...).
(function($) {
var isIE = false;
// conditional compilation which tells us if this is IE
/*@cc_on
isIE = true;
@*/
// Events to monitor if 'input' event is not supported
// The boolean value is whether we have to
// re-check after the event with a setTimeout()
var events = [
"keyup", false,
"blur", false,
"focus", false,
"drop", true,
"change", false,
"input", false,
"textInput", false,
"paste", true,
"cut", true,
"copy", true,
"contextmenu", true
];
// Test if the input event is supported
// It's too buggy in IE so we never rely on it in IE
if (!isIE) {
var el = document.createElement("input");
var gotInput = ("oninput" in el);
if (!gotInput) {
el.setAttribute("oninput", 'return;');
gotInput = typeof el["oninput"] == 'function';
}
el = null;
// if 'input' event is supported, then use a smaller
// set of events
if (gotInput) {
events = [
"input", false,
"textInput", false
];
}
}
$.fn.userChange = function(fn, data) {
function checkNotify(e, delay) {
var self = this;
var this$ = $(this);
if (this.value !== this$.data("priorValue")) {
this$.data("priorValue", this.value);
fn.call(this, e, data);
} else if (delay) {
// The actual data change happens aftersome events
// so we queue a check for after
// We need a copy of e for setTimeout() because the real e
// may be overwritten before the setTimeout() fires
var eCopy = $.extend({}, e);
setTimeout(function() {checkNotify.call(self, eCopy, false)}, 1);
}
}
// hook up event handlers for each item in this jQuery object
// and remember initial value
this.each(function() {
var this$ = $(this).data("priorValue", this.value);
for (var i = 0; i < events.length; i+=2) {
(function(i) {
this$.on(events[i], function(e) {
checkNotify.call(this, e, events[i+1]);
});
})(i);
}
});
}
})(jQuery);
Upvotes: 1