Michael
Michael

Reputation: 1397

Formating GWT TextBox as user types

I have some textboxes that I want to format as the user types. For example I want to have the value appear as a currency, $4506.98. I am using the TextBox.addKeyUpHandler to catch every change as the user types and format it; however, I might be displaying $4506.98 and the user pushes the 5 key, it will show $4506.985 until the user lifts up on the key when it finally updates it to $45069.85 (which is what I want it to show). I don't like how it shows 4506.985 for the short time the key is being pressed, and would like to fix that.

I couldn't get the KeyDownHandler to work properly either.

Here is my KeyDown handler

        final TextBox This = this;
        this.addKeyUpHandler(new KeyUpHandler(){

            public void onKeyUp(KeyUpEvent event) {
                String v = This.getText();
                if(v.equalsIgnoreCase("0.0")){
                    This.setText("");
                    return;
                }
                v = v.replaceAll("\\D+","");  //Get only digits
                v= v.replaceFirst("^0+(?!$)", ""); //remove leading zeros
                if(v.length() > 2){
                    This.setText("$"+v.substring(0, v.length()-2) + "." + v.substring(v.length()-2));
                } else if (v.length() == 2){
                    This.setText("$0." + v);
                } else if (v.length() == 1){
                    This.setText("$0.0"+v);
                }               
            }

        });

Upvotes: 0

Views: 325

Answers (2)

Michael
Michael

Reputation: 1397

I found the best way to do this is to use a KeyDownHandler. With KeyDown the TextBox.getText() doesn't return the new key so a lot more work is required. We have to look at event.getNativeKeyCode to find out the new key and add it to the text and format the text. In my case I had to handle a lot of keys, all the number keys, and allow for backspace, delete, copy, paste, cut, home and end. I also needed to handle cursor position of the text since I might be adding or deleting text to get the format right.

For the most part this code works. If the user has selected text this won't work as the user expects, but adding more code you should be able to catch that case.

import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.logging.client.ConsoleLogHandler;
import com.google.gwt.user.client.ui.TextBox;

import static com.google.gwt.event.dom.client.KeyCodes.*;

public class MoneyBox extends TextBox {

    MoneyBox(){
        final MoneyBox This = this;
        this.addKeyDownHandler(new KeyDownHandler(){

            @Override
            public void onKeyDown(KeyDownEvent event) {
                if(event.isLeftArrow() 
                    || event.isRightArrow()
                    || event.getNativeKeyCode() == KEY_SHIFT
                    || event.getNativeKeyCode() == KEY_CTRL
                    || event.getNativeKeyCode() == KEY_END
                    || event.getNativeKeyCode() == KEY_HOME
                    || event.getNativeKeyCode() == KEY_TAB
                    || (event.getNativeKeyCode() == KEY_V && event.isControlKeyDown())  //paste
                    || (event.getNativeKeyCode() == KEY_C && event.isControlKeyDown())  //copy
                    || (event.getNativeKeyCode() == KEY_X && event.isControlKeyDown())  //cut
                  ) {
                    return;
                }
                String numbersOnlyText = This.getText().replaceAll("\\D+","");
                int curPosition = This.getCursorPosNumber();

                if(!event.isAnyModifierKeyDown()){
                    if(event.getNativeKeyCode() == KEY_ZERO
                            || event.getNativeKeyCode() == KEY_NUM_ZERO){
                        if(curPosition != 0){  //puttint a
                            numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("0" + numbersOnlyText.substring(curPosition));
                            curPosition++;
                        }
                    } else if (event.getNativeKeyCode() == KEY_ONE
                                || event.getNativeKeyCode() == KEY_NUM_ONE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("1" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_TWO
                            || event.getNativeKeyCode() == KEY_NUM_TWO) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("2" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_THREE
                            || event.getNativeKeyCode() == KEY_NUM_THREE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("3" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_FOUR
                            || event.getNativeKeyCode() == KEY_NUM_FOUR) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("4" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_FIVE
                            || event.getNativeKeyCode() == KEY_NUM_FIVE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("5" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_SIX
                            || event.getNativeKeyCode() == KEY_NUM_SIX) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("6" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_SEVEN
                            || event.getNativeKeyCode() == KEY_NUM_SEVEN) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("7" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_EIGHT
                            || event.getNativeKeyCode() == KEY_NUM_EIGHT) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("8" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_NINE
                            || event.getNativeKeyCode() == KEY_NUM_NINE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition).concat("9" + numbersOnlyText.substring(curPosition));
                        curPosition++;
                    } else if (event.getNativeKeyCode() == KEY_BACKSPACE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition-1)+numbersOnlyText.substring(curPosition);
                        curPosition--;
                    } else if (event.getNativeKeyCode() == KEY_DELETE) {
                        numbersOnlyText = numbersOnlyText.substring(0, curPosition)+numbersOnlyText.substring(curPosition+1);
                    }
                }
//              if(numbersOnlyText.length() == 1 ){
//                  curPosition += 2;
//              } else if (numbersOnlyText.length() == 2 ){
//                  curPosition += 1;
//              }
                String newText = formatMoney(numbersOnlyText);
                curPosition += newText.replaceAll("\\D+","").length() - numbersOnlyText.length();
                This.setText(newText);
                event.preventDefault();
                This.setCursorPosNumber(curPosition);

            }

        });

        this.addChangeHandler(new ChangeHandler(){
            @Override
            public void onChange(ChangeEvent event) {
                This.setText(formatMoney(This.getText()));
            }
        });
    }

    private static String formatMoney(String v){
        v = v.replaceAll("\\D+","");  //Get only digits
        v= v.replaceFirst("^0+(?!$)", ""); //remove leading zeros
        if(v.length() > 2){
            v = "$"+v.substring(0, v.length()-2) + "." + v.substring(v.length()-2);
        } else if (v.length() == 2){
            v = "$0." + v;
        } else if (v.length() == 1){
            v = "$0.0"+v;
        }
        int count = 0;
        for(int i = v.indexOf('.')-1; i>0; i--){
            if(count%3==0 && count !=0){
                v = v.substring(0, i+1) + "," + v.substring(i+1);
            }
            count++;
        }
        if (v.equalsIgnoreCase("$0.00"))
            return "";
        else
            return v;
    }


    public int getCursorPosNumber() {

        int superPos = super.getCursorPos();
        int count = 0;
        for(int i =0; i< superPos; i++){
            if(this.getText().charAt(i) != '.'
                    && this.getText().charAt(i) != ','
                    && this.getText().charAt(i) != '$'){
                count++;
            }
        }
//      GWT.log("getCursorPos " + String.valueOf(count) + " " + String.valueOf(superPos));
        return count;
    }


    public void setCursorPosNumber(int pos) {
        int count = 0;
        for(int i =0; i<this.getText().length(); i++){
            if(this.getText().charAt(i) != '.'
                    && this.getText().charAt(i) != ','
                    && this.getText().charAt(i) != '$'){
                count++;
            }
            if (count == pos){
                super.setCursorPos(i+1);
//              GWT.log("setCursorPos " + String.valueOf(i+1) + " " + String.valueOf(pos));
                return;
            }
        }
        GWT.log("setCursorPos " + String.valueOf(this.getText().length()) + " " + String.valueOf(pos));
        super.setCursorPos(this.getText().length());
    }
}

Upvotes: 1

Fabian
Fabian

Reputation: 413

KeyUpHandler is the way to go if you want to manipulate the value of the TextBox. Also note that most of the String helper methods are not working in GWT, like equalsIgnoreCase, replaceAll and replaceFirst! You have to use the GWT Regexp class to use regular expression.

Here's a little working example:

final TextBox currencyTextBox = new TextBox();
currencyTextBox.addKeyUpHandler(new KeyUpHandler() {
    @Override
    public void onKeyUp(final KeyUpEvent event) {
        final String value = currencyTextBox.getText();

        final RegExp regExp = RegExp.compile("^[0-9]*$");
        final boolean onlyNumbers = regExp.test(value);
        if (onlyNumbers) {
            currencyTextBox.getElement().getStyle().clearBackgroundColor();
        } else {
            // there are not only digits
            currencyTextBox.getElement().getStyle().setBackgroundColor("red");
        }
    }
});

Upvotes: 0

Related Questions