0

I have a form where elements such as input and select can be updated in many different ways (user entry, copy/paste, select options added or removed programmatically, value updated programmatically, autocomplete). Rather than trying to catch all these actions, I'd rather observe changes to the element properties.

The easiest way is to rely on the propertychange event, unfortunately it only works on IE 10 and below.

What are my options for IE 11 and other browsers like Chrome? I have heard of methods like Object.defineProperty for objects, but I am not sure how it would apply to my form elements. I also looked into mutation observers, but I don't see how they would help with input elements.

Any pointers would be appreciated.

[edit] I am getting comments that this question is too broad. I understand, and I was actually hoping that there's already a clear answer, as it seems to me that it's such a common request.

To make it more specific, here is the immediate issue I have to deal with: how to detect a programmatic change to an input element value, in IE 11 and Chrome?

Christophe
  • 24,147
  • 23
  • 84
  • 130
  • can't you create a central handler for `onchange` for all of them? – Yuriy Galanter Oct 09 '13 at 17:09
  • 1
    this question although could have been a bit more specific, does not deserve a downvote imho – Konstantin K Oct 09 '13 at 17:10
  • 1
    @YuriyGalanter the `onchange` event doesn't see programmatic changes – Christophe Oct 09 '13 at 17:13
  • 1
    How about: http://stackoverflow.com/questions/1847893/js-events-hooking-on-value-change-event-on-text-inputs ? Or http://stackoverflow.com/questions/1759987/listening-for-variable-changes-in-javascript-or-jquery ? – Ian Oct 09 '13 at 17:17
  • @Ian thx for the pointers. The IE 11 issue is something new, and so far I haven't found any post or answer that tackles it. – Christophe Oct 09 '13 at 17:24
  • @Christophe Does IE 11 not support `Object.prototype.watch`? Even if it doesn't, I'm sure it supports `Object.defineProperty`, which is used in a polyfill for `Object.prototype.watch` that I provided – Ian Oct 09 '13 at 17:27
  • @Ian it does. Is this explained in one of the links you provided? I didn't see it... – Christophe Oct 09 '13 at 17:29
  • @Christophe Yeah, sorry, it's in the first answer in my second link. https://gist.github.com/eligrey/384583 is the polyfill (even MDN suggests it on their `Object.prototype.watch` page). So you'd include that snippet first, then it should be available. Although there probably needs to be an extra check for `Object.defineProperty` being supported (so that it doesn't crash in older IE). So this polyfill could be combined with the first answer in the first link I provided, hopefully providing complete cross-browser support – Ian Oct 09 '13 at 17:32
  • @Ian damn, I still can't see it. Would you mind making this an answer? It seems to be what I'm looking for, I just need to understand if it works on DOM elements, not just on js objects. – Christophe Oct 09 '13 at 17:37
  • @Christophe Yeah, let me put it all together. Sorry for the confusion of links/posts. Hopefully I can get something working that works for you in IE11 – Ian Oct 09 '13 at 17:38
  • @Ian very interesting link. I did some testing on Chrome, I can detect the input value change but not the select length change http://jsfiddle.net/8Y6v3/1/ – Christophe Oct 09 '13 at 20:21

2 Answers2

0

For select boxes use change events. You can bind to the same event with input boxes too, but keep in mind that inputs of type text will only trigger the change event once blurred (if I remember correctly). You may need to look into custom plugins for that, e.g. http://zurb.com/playground/jquery-text-change-custom-event

Also if modifying the value of an input using jQuery .val() you may have to trigger the change event explicitly using $("input.my-input").change() with no arguments

Konstantin K
  • 1,287
  • 2
  • 10
  • 18
  • 1
    The issue is that change events only cover half of my needs. They don't react to programmatic changes. – Christophe Oct 09 '13 at 17:12
  • my last paragraph was exactly about that :) I've had to deal with this problem a few times before and always had to reserve to calling the "update" function any time i had to change the value of an input programmatically – Konstantin K Oct 09 '13 at 17:16
  • 1
    in my case, the changes could be made by other libraries than jQuery or applications written by other people, that's why I am trying to observe the result. – Christophe Oct 09 '13 at 17:27
0

I don't think the solution you are looking for exists, at least not cross browser, so any solution to this problem will involve some sort of convention/code discipline on your part.

If you have control over all of the related code this shouldn't be too much of a problem; if you don't you may need to resort to a setInterval() that polls the fields you care about.

Konstantin's answer covers most cases related to direct user input. For programmatic changes if you are using a library like jQuery you can intercept the calls:

var oldValFn = $.fn.val;
$.fn.val = function() {
    var result = oldValFn.apply(this, arguments);
    if(arguments.length > 0) {
        // value is being set to arguments[0]
    } else {
        // value is being retrieved, you probably don't do anything here.
    }
    return result;
};

You may also want to add a delegated keydown/keypress handler to report on intermediate changes to text fields in case you are unwilling to wait for blur events:

var oldVal;
$(document).on('keydown keypress', function(e) {
    $(e.target).val(); // this will be the pre-change value
    setTimeout(function() {
        $(e.target).trigger('change'); // the value will be updated _after_ the event finished bubbling
    });
})
Mike Edwards
  • 3,642
  • 15
  • 21
  • It almost always isn't a great idea to extend built-in functions (in this case the .val function provided by jQuery) – Konstantin K Oct 09 '13 at 17:21
  • @KonstantinK Unless you have a reason, there's nothing wrong with it. This answer seems to leave in the original functionality (although that probably needs to be checked), as well as doing something custom – Ian Oct 09 '13 at 17:22
  • If you care to link to something that backs up your opinion I'd love to read it. As long as you delegate the call down through the original function with .apply(this, arguments) and route the original result back out I have never run into any issues. You may not have a choice if you really want the functionality you are asking about. – Mike Edwards Oct 09 '13 at 17:24
  • 1
    in my case, the changes could be made by libraries other than jQuery or applications written by other people, that's why I am trying to observe the result. I agree about the polling technique, and that's what I have been using so far, but I am hoping I can do better. – Christophe Oct 09 '13 at 17:46
  • @MikeEdwards Interesting point. I always took the rule "don't extend native functions/objects" for granted without questioning it too much. A quick search produced this: http://stackoverflow.com/questions/14034180/why-is-extending-native-objects-a-bad-practice (which doesn't really have any references). Ironically, I did once do exactly that because there was no other way: something very similar to this http://stackoverflow.com/a/3534895/1099743 . I think it's an interesting question and I can't find any relevant sources, so gonna create a new thread – Konstantin K Oct 10 '13 at 09:14
  • You may wanna share your point of view here: http://stackoverflow.com/questions/19291917/extending-native-jquery-functions it's not just me who thinks that extending native code should be avoided if by any means possible – Konstantin K Oct 10 '13 at 09:56