2

I know I can use watch to bind a callback that will be triggered when object property changes. And this does work on generic objects like:

{'a':1, 'b':'7'}

So, I thought that I can simply do this to bind a callback that will trigger when input field value changes:

var inputDomElement = document.getElementById('someInputElement');
inputDomElement.watch('value',function (id, oldval, newval) {
    alert(oldval);
    alert(newval);
});

But this doesn't work. Simply doesn't trigger. No alert boxes. I've tried it in Firefox 5 and Google Chrome (latest).

Is this not how watch works? Is watch simply doesn't work on DOM elements? I thought that they're simply objects - aren't they?

UPDATE 1:

Here's MDN info about what watch is: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch

UPDATE 2:

I cannot use change event. because change only triggers when text element catches blur. Meaning that it'll only trigger when user switches from this textfield to another one. It's not in any way dynamic for when for example checking if this username or email address already taken which I'd like to happen on each distinct change.

halfer
  • 19,824
  • 17
  • 99
  • 186
Stann
  • 13,518
  • 19
  • 65
  • 73
  • The banner at the top of the MDN page has "Non-standard" in yellow. May account for why it doesn't work. – Alastair Pitts Aug 05 '11 at 03:22
  • 2
    It does work in all modern browsers: Firefox 3+, Google Chrome, IE 9+, SAFARI v. 4+. Also - I do mention in my question that I've tried it in supporting browser. – Stann Aug 05 '11 at 03:23
  • 5
    Please refrain from continuing to update your original question with "Still waiting" changes. Not having an accepted answer implies that you are looking for the right answer. You do not need to continue "bumping" your question. – Alastair Pitts Aug 05 '11 at 03:26

3 Answers3

4

The DOM is written in C/C++ where the concept of getting and setting a Javascript variable doesn't exist as you or I would often imagine it. You probably imagined the code to be implemented similar to what is below. Unfortunately Object.watch is never initiated because the DOM isn't constantly updating the Javascipt value, but Javascript is requesting an update from the DOM.

input.onuserchangevalue = function(){
   input.value = 'new user input'
}

Thinking how the DOM commonly works, each element has dozens of potential properties.

  • innerHTML,value,style.cssText,name,id,style.background,style.backgroundColor

Imagine if the DOM underlining code had to constantly update every DOM elements Javascript properties %) Memory and CPU cycles would go through the roof having to ensure the properties matched the display value. The DOM's internals would also have to check if the Javascript value has potentially changed.

Reality - Red Pill

Basically the DOM isn't giving info to javascript, but Javascript is requesting the info from the DOM. This is a decent Javascript interpretation of what is going on underneath.

Object.defineProperty(input, "value", {
    get : function(){ /* get C/C++ DOM value */ },
    set : function(){ /* change C/C++ DOM value */ }
   });

This explains why the DOM is often the bottleneck for Javascript. Javascript has to request/set the internal DOM values every time you interface with the DOM.

Lime
  • 13,400
  • 11
  • 56
  • 88
  • The way you're using .watch() and how it's shown in the example for the MDN article they are watching javascript objects created in javascript, not DOM objects. I did come across this question that may help you in what you want to do: http://stackoverflow.com/questions/1269633/javascript-watch-for-object-properties-changes – Alexander Kahoun Aug 05 '11 at 05:34
  • @Alexander The issue is with how the underlying DOM has been implemented, not with using `Object.defineProperty` vs `__defineGetetr__/__defineSetter__`. I put Javascript examples above to demonstrate how it **kinda** woks internally. – Lime Aug 05 '11 at 05:38
  • sorry, I think my initial comment was unclear. I completely agree with you and up-voted. :) The comment was meant to be an addendum to your answer and directed at Andre. The time to edit the original comment has passed unfortunately. – Alexander Kahoun Aug 05 '11 at 05:41
  • 1
    @Lime: Thank you. So - the moral of the story is, that DOM API and JS API are different things and when one creates JS object by using getElementById - this will simply get "right now data" from the DOM element, and that object will not be synced with the DOM data, So - I can bind watch to that created JS object - but it'll never going to trigger, because it'll never get updated - right? – Stann Aug 05 '11 at 05:47
  • 1
    Yeah. Javascript is interfacing with the DOM which is interfacing with the DOM's underlying C/C++ code. Javascipt -> DOM -> C/C++ – Lime Aug 05 '11 at 05:50
2

You need to use jQuery Objects, not DOM Objects. There is a difference.

document.getElementById("someID") //returns DOM Object

$('#someId')  //returns jQuery Object

Note: you could doe something strange like this:

$(document.getElementById("someID"))  //returns a jQuery Object

this would work

$('#someInputElement').watch('value',function (id, oldval, newval) {
    alert(oldval);
    alert(newval);
});
John Hartsock
  • 85,422
  • 23
  • 131
  • 146
  • huh? i don't remember "watch" being in jQuery. is this a plugin? – Stann Aug 05 '11 at 02:08
  • @Andre Yes, it is a plugin. Sorry didn't denote that in my answer and OP did not in his question. I just made the assumption this was what he was using as I have used it before. – John Hartsock Aug 05 '11 at 02:12
  • I see. I'm aware of several plugins, but I was rather interested to know why default javascript watch implementation doesn't work: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch – Stann Aug 05 '11 at 02:17
1

if you want to track changes on a text element, why not just use the .change() method?

http://jsfiddle.net/rkw79/qTTsH/

$('input').change(function(e) {
    $('div').html('old value: ' + e.target.defaultValue + '<br/>'
                  + 'new value: ' + e.target.value);
})

For instant change, use .keyup(): http://jsfiddle.net/rkw79/qTTsH/1/

rkw
  • 7,287
  • 4
  • 26
  • 39
  • because change only triggers when text element catches blur. Meaning that it'll only trigger when user switches from this textfield to another one. It's not in any way dynamic for when for example checking if this username or email address already taken which Id' like to happen on each change. For example - take a look at google or yahoo registration pages. – Stann Aug 05 '11 at 03:08
  • @Andre: what about using .keyup then? Check the updated post – rkw Aug 05 '11 at 03:13
  • 1
    Yes - I suspected that this will be the next thing you'll offer:) The thing is - think about how many ways there are to change input field: 1) keypresses 2) copy/paste via either context menus or via keyboard shortcuts 3) Input value was modified with JavaScript 4) auto-completed by browser or one of the browser addons. It's easier to track just the final result then all the ways there are to get there. – Stann Aug 05 '11 at 03:16
  • 1
    watch method is really the best way to track any value changes. The only question I'm trying to answer is - why native watch way doesn't work for DOM elements. Though I can easily use some pugins like: http://plugins.jquery.com/project/watch – Stann Aug 05 '11 at 03:20
  • @Andre, ah, that does sound useful. Let us know if you find a solution that doesn't involve polling. Check out this SO post and see if it's useful: http://stackoverflow.com/questions/1269633/javascript-watch-for-object-properties-changes – rkw Aug 05 '11 at 03:34
  • 1
    There isn't one for DOM element values. trust me on this one. I've spend some time diggging around and ended up writing my own jQuery plugin. Polling is just fine if correctly implemented. Here it is if you're interested (dead simple): https://github.com/nixd3v/jquery.monitor – ThatGuy Aug 07 '11 at 19:42