Search code examples
javascriptjquerykeypressjquery-events

How to obtain full value inside jQuery's keypress event?


I'm writing some jQuery which intercepts the value entered in an input field and determines whether to allow or to prevent the typed value.

I need to get the next value, i.e., what the value will be were I to permit the key-press, and I need to know this value at a point before it is displayed, so I'm using the keypress event.

My question is: inside the keypress event, how can I tell what the resultant value would be were I to permit the key-press? What is the 'potential value'?

If I write out the key-press event object to the console and inspect the properties, I can see that currentTarget.value shows this 'potential value'. However, if I use this property inside the keypress event then it returns only the value prior to the context key-press.

For example, if the user types "a" into an empty text box bound to the following jQuery

$(":input").on("keypress", function(e) {
    console.log(e);
    console.log(e.currentTarget.value);
});

Digging down through the first console output (e) shows that currentTarget.value = "a".

But the second console output (e.currentTarget.value) will show "".

If the user was then to type "b" into that same text box then: Manually inspectng e and locating currentTarget.value displays "ab"; Dumping e.currentTarget.value from inside the event displays "a".

Can anyone explain how I can get this 'potential value' while inside the keypress event?


Solution

  • Not the prettiest of solutions (you can see the would be result just before it's reverted), but to save the trouble of discerning between arrow/control and input keys etc, you could store the original value in keypress and revert to that in keyup if needed (also storing the selection positions for complete reversion)

    $(":input").keypress(function(e) {
        $(this).data('orgValue', {value: this.value, pos: this.selectionStart, selend:this.selectionEnd});
    }).keyup(function(e){
        var val = this.value;
        if(!somevalidation(val)){
            var org =$(this).data('orgValue');        
            this.value = org.value;
            this.selectionStart = org.pos;
            this.selectionEnd = org.selend;
        }
    });
    

    Example fiddle

    Edit

    Did some testing, but jquery makes predicting the outcome relatively easy. Not only does it fill the key property, it also fills other properties on its event on which the type of key can be checked. While testing charCode seems to be 0 for 'non input' keys. The straight forward would be:

    $(":input").keypress(function(e) {
        if(!e.charCode)return; //is 0 for non input
        var cur = this.value; //current value
        var val = cur.substring(0,this.selectionStart)
            + e.key
            + cur.substring(this.selectionEnd);     
        return cur=== val //unchanged
            || somevalidation(val);        
    });
    

    But that would not include deletes/backspaces, to handle those as well:

    $(":input").keypress(function(e) {
        var key,start = this.selectionStart ,end = this.selectionEnd;
        if(e.charCode)
            key = e.key;
        else{
            if(e.keyCode===8 || e.keyCode===46){
                key = '';
                if(end===start){
                    if(e.keyCode===8)
                        start--;
                    else
                        end++;
                }
            }
            else
                return true; //charCode is 0 for non input 46 = delete 8 = backspace
        }
        var cur = this.value; //current value
        var val = cur.substring(0, start) + key + cur.substring(end);     
        return cur=== val //unchanged
            || somevalidation(val);        
    });
    

    Fiddle

    While testing this seemed to behave as expected. An other way might be have a hidden input field, send the keys there and examine its results, but the above should do the trick.