views:

800

answers:

4

Hi all,

I have a text input that its content is changed by a script not by user. So I would want to fire an event when the value changes. I can't find a suitable event for that. I event found this on StackOverflow but is not the solution I'm looking for.

How to make this work with jQuery and a text input where the value is set like this:

myTextControl.value = someValue

Here I want to fire an event to see the new value.

A: 

You'll need to listen to keyboard events when the element you're watching has focus.

Diodeus
As implied in the question, it's not by user interaction, so how your answer has any validity?"""I have a text input that its content is changed by a script not by user."""
Esteban Feldman
A: 
var oldVal = $('#myTextControl').val();

//Your script that changes the value

if(oldVal != $('#myTextControl').val())
{
//Your content has changed, do something
}
Toby
I need an EVENT... so I know when it changed and do something about it. In your example there is an explicit flow, not my case... the value can change on an AJAX call or whatever and I cant hook on that so I need to get an event fired. Or a decorator to .value?
Esteban Feldman
+1  A: 

You can add a normal event listener to your input field like so. (using jQuery)

$(myTextControl).change(function() {
    ...
    /* do appropriate event handling here */
    ...
});


Ok considering that the javascript which changes the input value isn't controlled by you it gets difficult. You are left with two options:

1.) Crossbrowser compatible: Implement polling of input value with a function which continuously checks if the value changed. (Something along these lines).

//at beginning before other scripts changes the value create a global variable
var oldValue = myTextControl.value;

function checkIfValueChanged() {
    if(myTextControl.value != oldValue) {
        $(myTextControl).trigger("change");
        clearInterval(checker);
    }
}

//every 500ms check if value changed
var checker = setInterval('checkIfValueChanged()', 500);

Note: If your script or the user can change the value too you must implement something to catch this in order not to trigger the change event multiple times.

If the value can change multiple times by the external script just let the interval function run instead of canceling it and just update oldValue;

2.) AFAIK Not supported yet by all browsers (? test it on the ones you need to support)

You could bind to a special DOM Level 3Event: DOMAttrModified (in Firefox, maybe others too I think Opera has it too, Safari??, Chrome??) and in IE of course it has a different name propertychange (and is proprietary and different from the W3C behavior)

Now ideally you could combine the two options and check if support for DOMAttrModified or propertychange is there and use accordingly or fallback to the polling solution.


Reading links

W3C DOM Mutation Events

W3C DOMAttrModified Event

MSDN DHTML propertychange Event

jQuery CSS Property Monitoring Plug-in updated

Last link is some guy which basically already made a jQuery plugin doing the things described by me (untested by me, provided just as a reference)

jitter
I have no access to the part where the control is changed so I cannot manually trigger that event. That's why I want an event on value change.
Esteban Feldman
Check rewritten answer
jitter
+3  A: 

I can't find a suitable event for that.

Yeah, there isn't one.

There are DOM Mutation Events, but they aren't supported well cross-browser, and don't fire for form values anyway as those aren't reflected in attributes (except in IE due to a bug).

In Mozilla only, a JavaScript watch could be set on the value property to catch scripted changes. In IE only, a JScript onpropertychange handler could be set to catch both scripted and user-driven changes. In other browsers you would have to use your own interval poller to look for changes.

function watchProperty(obj, name, handler) {
    if ('watch' in obj) {
        obj.watch(name, handler);
    } else if ('onpropertychange' in obj) {
        name= name.toLowerCase();
        obj.onpropertychange= function() {
            if (window.event.propertyName.toLowerCase()===name)
                handler.call(obj);
        };
    } else {
        var o= obj[name];
        setInterval(function() {
            var n= obj[name];
            if (o!==n) {
                o= n;
                handler.call(obj);
            }
        }, 200);
    }
}

watchProperty(document.getElementById('myinput'), 'value', function() {
    alert('changed!');
});

This is highly unsatisfactory. It won't respond to user-driven changes in Mozilla, it allows only one watched property per object in IE, and in other browsers the handler function will get called much later in execution flow.

It's almost certainly better to rewrite the parts of script that set value to call a setValue wrapper function instead, that you can monitor for changes you want to trap.

bobince
lol 14min ago. damn browser didn't tell me you already posted what I was writing at. whatever
jitter
IE can handle multiple handlers via `obj.attachEvent('onpropertychange', ...)`, and `__defineSetter__('value', ...)` can be used on DOM nodes to similar effect in FF2+ (including FF2 where although it's documented as not functional on DOM nodes, I can verify it works), Opera 9.5, Safari 3, and Chrome 1. The only divergence from IE's implementation is IE fires the handler not only on programmatic setting but also during key events.
Crescent Fresh