views:

543

answers:

5

I have a single form field and I need to be able to detect when the field changes and execute some additional code using the new value of the field. I only want to execute the code if the key pushed actually changes the value of the text box. Here's the solution I came up with.

function onkeypress(e) {
  var value = this.value;
  // do something with 
}

function onkeyup(e) {
  if ( e.which == 8 || e.keyCode == 46 ) { // delete or backspace keys
    this.onkeypress(e);
  }
}

There's just one problem though. onkeypress is fired before the field's value is updated, so when I grab the value, I'm getting the previous value. I would use keyup exclusively if I knew a way to test whether the key changed the value or not, but some characters (like the arrow keys) have no effect on the field's value.

Any ideas?

+1  A: 

have another conditional:

if(e.keyCode > 31  && e.keyCode < 127) {
    value = this.value + e;
}

This would catch any low level ascii symbol entered by the keyboard outside of the special char range.

EDIT: (32 is space)

function onkeyup(e) {        
  if ( e.which == 8 || e.keyCode == 46 ) { // delete or backspace keys 
    switch(e.keyCode) {
      case 32:
      case 48..90:
      case 96..111:
      case 188:
      case 190..192: 
      case 219..222:
          value = this.value + e;
          break;
      default: 
          break;
    }       
    this.onkeypress(e);        
  }        
}
Joel Etherton
Yah, that's what I was meaning :) Sorry for the vagueness. I should have been more specific that the conditional needed to be nested.
Joel Etherton
Actually, I just realized that this won't work, because the key codes don't necessarily match up with ascii codes. See https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent
spudly
Eh, it still works, you just have to adjust the numbers. Let me try an edit of the conditional.
Joel Etherton
A: 

It's kind of a hack, but you can put the previous value in a property of the textbox (called "expando attributes")

function onkeypress(e) {
  this.oldvalue = this.value;
}

function onkeyup(e) {
  if (this.value != this.oldvalue) {
    // do something
  }
}
Philippe Leybaert
A: 

The way I do this is simply with a variable along the lines of prevValue. At the end of the key press function, store the value in that variable, and only execute the function again if the value doesn't equal that previous value.

Nate B
A: 

You could store the old value and detect if it changed:

function keyUpHandle(e) {
  if (this.prevValue && this.prevValue != this.value) {
    // do something
  }
  this.prevValue = this.value;
}
gnarf
A: 

Here's my final solution, which uses a prevValue variable but doesn't pollute the global namespace (window) or the dom element's properties.

(function() {
  var input = document.getElementById('input_box'),
      prevValue;

  input.onkeyup = function(e) {
    if ( this.value != prevValue ) {
      prevValue = this.value;
      // execute some more code here...
    }
  }
}());

Notice above that the onkeyup function serves as a closure around the prevValue variable. This prevents the namespace pollution so I don't have to create a global variable or attach a property to the input element itself. This is as elegant as I can get it. I actually wrote mine in jQuery but thought the answer itself should be pure JavaScript...

spudly