3

Possible Duplicate:
keydown event new value

Didn't find that answer I was looking for, tried for a while, getting desperate:

My goal is to have a numeric non-negative input field that can be decimal and have a single character suffix that is a letter (legel suffix collection exists).

On a technical level - I need to be able to reject the input character, and I need both the values (before and after the input).

Approaches I Tried & Failed:

Keydown \ Keypress events:

cannot get the "after", just the before and the char/KeyCode. That's a problem since I don't know where to insert the new char in the old value (not neccessarily at the end..) - need a way to get the "after" or at least the index where the char belongs.

Keyup event:

Doesn't have the before value, but even worse - this doesn't fire when there's a long press ("00000000000000000...") and so I can't reject the input.

OnChange/change/blur - only fires on lose focus, not the functionality I need.

any ideas?

Community
  • 1
  • 1
EhudFisher
  • 217
  • 1
  • 5
  • 10
  • I would add a monitor using setInterval that triggers on for example focus and stops onblur – mplungjan Dec 19 '12 at 12:42
  • You could use the `input` event, which gives the "after" text. – pimvdb Dec 19 '12 at 12:43
  • It's quite simple, IMO: whereas `e.keyCode || e.which` gives you the key pressed, `e.target || e.srcElement` gives you the DOM element on which the event was fired, therefore `(e.target || e.srcElement).value` will give you the current/before value. Using a closure, you can keep track of the cursor position, of course, or you can bind a second event listener (onkeyup), that has access to the _before_ value. There might even be an event property that gives you the cursor position (something like `selectionStart`...) – Elias Van Ootegem Dec 19 '12 at 12:46
  • 1
    You could use `selectionStart` and `selectionEnd` properties to get the position – Bergi Dec 19 '12 at 12:46
  • 2
    This type of interface is usually disliked by users. You really only care that the input has a valid value at the time the value is used for something. Usually that's when data is submitted to the server. Before then, you don't care what the value is. – RobG Dec 19 '12 at 12:52
  • The only ther thing I can think of is using `setInterval` to periodically check the content of the input box, but I don't think that it would be the best way to do it. – starbeamrainbowlabs Dec 19 '12 at 12:56
  • @RobG - Unfortunately, I don't have the luxury of waiting for submission, as every change in the value is immediately reflected in the UI (say, in a graph) and therefore must be valid upon entry. – EhudFisher Dec 19 '12 at 13:03
  • possibly related: [keydown event new value](http://stackoverflow.com/questions/10911047/keydown-event-new-value) – Bergi Dec 19 '12 at 13:22
  • @EhudFisher—if the value is invalid, give the user a hint and do nothing to the UI. – RobG Dec 19 '12 at 20:37

3 Answers3

1

How about a very brute method of saving the current value in a hidden field, and updating it when necessary? This will allow you to access the "before" and "after" states.

It's not a great approach but considering it's close to impossible to get the previous value, I would consider it.

Nir
  • 3,963
  • 8
  • 37
  • 51
0

I would rather point you to another direction. In an earlier project i had the same issue. I soved it by using a jQuery Plugin. A so called "masked input".

You then will be able to give a regular expression on how the input to that field should be made by the user.

This is the GitHup Ressource of the plugin! https://github.com/digitalBush/jquery.maskedinput

You can find the examples and documentation here!

An example:

jQuery(function($){
    $("#element-id").mask("9.99a");
});

Many options available, just check out the ability to create your own masks!

Scriptlabs
  • 498
  • 3
  • 16
  • 1
    How does it work? Is that just a polyfill for the HTML5 `pattern` attribute? – Bergi Dec 19 '12 at 13:16
  • No, this is the "brutal" javascript way! It's using RegExpObject.test(string); Javascript Regex and a char buffer to test against given mask! – Scriptlabs Dec 19 '12 at 13:24
  • A "char buffer"? Is that a solution to the OPs event problem? – Bergi Dec 19 '12 at 13:47
  • I think so, by preventing input shown before regex is true and formatted inside the mask. Output is generated by the script. Take a look at the code, really short and clean. https://raw.github.com/digitalBush/jquery.maskedinput/master/src/jquery.maskedinput.js – Scriptlabs Dec 19 '12 at 14:08
0

It's quite impossible to know onkeypress what the value after it will be. Yes, we know the pressed keys (and modifiers) and we know the selection/cursor so we could simulate what will happen, and preventDefaultAction of the keypress event. But we make assumptions about keyboard layout that might be wrong, and there are so many edge case input methods that we can hardly handle all of them.

The solution I came up with is to manually maintain the state of the input, and look for changes as often as possible. If one happens, the handler is fired with previous and after state and returns the new value. This is what is looks like:

function handler(afterval, prevval) {
    // do something
    return afterval; // return val can be used for length limits etc
}
(function(el, handler) {
    var curval = el.value;
    function check(e) {
        if (el.value != curval)
            curval = el.value = handler(el.value, curval);
    }
    $(el)
      .on("keyup input keydown change mouseup cut paste focus", check)
      .on("keypress", function(e) {
        check(e);
        setTimeout(check, 0); // also check after keypress as soon as possible
      });
})(handler);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375