3

I'm trying to restrict input into a GWT TextInputCell for things like monetary values, dates, SSNs, etc. I'd like to restrict the character that they can type in to the field using a regular expression (ideally). I'm guessing that the only way to do this is to override the onBrowserEvent method on the TextInputCell, but I haven't been able to get it to work.

What is the best way to mask my input cells?

jzd
  • 23,473
  • 9
  • 54
  • 76
Javid Jamae
  • 8,741
  • 4
  • 47
  • 62

2 Answers2

4

The onBrowserEvent method receives a NativeEvent, which has a preventDefault method. You probably want to call that preventDefault method whenever getKeyCode on the native event returns a character that you want to block.

See also the KeyCodes class, which can be handy for testing for special keys.

David
  • 5,184
  • 3
  • 41
  • 67
  • Excellent! I finally got something working with capturing keyup/keydown events and trimming, but the preventDefault works much better! I'll post my ultimate solution as a separate answer, but I'll accept yours. – Javid Jamae Jan 18 '11 at 23:50
2

So here is my solution (based on David's great feedback):

First, there is a limitation in the TextInputCell in that it can't handle native keypress events, so I had to create a near-exact copy of the class and add the keypress event type to the constructor where it passes in the event types that the cell can handle to the super constructor. Let's call this class KeyPressableTextInputCell. See this thread where I discussed this solution: Why isn't the keypress event being sent to GWT's TextInputCell.onBrowserEvent() method?

Then, I created a MaskedTextInputCell class that overrides the onBrowserEvent() method and prevents invalid keystrokes as they're typing, and also checks the overall form of the field. For example, valid monetary keystrokes are 0-9 and the decimal point. The overall form has to be numbers only, with only a single decimal point. Both of these checks are done using a strategy interface that I called ValidationStrategy and put directly in the MaskedTextInputCell.

public class MaskedTextInputCell extends KeyPressableTextInputCell {
    public interface ValidationStrategy {
        public boolean matches(String valueToCheck);
    }

    private ValidationStrategy overallFormValidationStrategy;
    private ValidationStrategy validKeystrokeValidationStrategy;

    public MaskedTextInputCell(ValidationStrategy overallFormValidationStrategy,
            ValidationStrategy validKeystrokeValidationStrategy) {
        this.overallFormValidationStrategy = overallFormValidationStrategy;
        this.validKeystrokeValidationStrategy = validKeystrokeValidationStrategy;
    }

    @Override
    public void onBrowserEvent(Element parent, String value, Object key, NativeEvent event,
            ValueUpdater<String> valueUpdater) {
        super.onBrowserEvent(parent, value, key, event, valueUpdater);

        if ("keypress".equals(event.getType())) {
            String keystroke = String.valueOf((char) event.getCharCode());
            handleInvalidKeystroke(keystroke, event);
        } else if ("blur".equals(event.getType()) || "keyup".equals(event.getType())) {
            String valueInInputElement = getInputElement(parent).getValue();
            handleInvalidOverallForm(valueInInputElement);
        }
    }
    protected void handleInvalidOverallForm(String valueOfEntireField) {
        if (!overallFormValidationStrategy.matches(valueOfEntireField)) {
            //You could fire an event here to turn the cell red...
            GWT.log("Invalid form.");
        }
    }
    protected void handleInvalidKeystroke(String keystroke, NativeEvent event) {
        if (!validKeystrokeValidationStrategy.matches(keystroke)) {
            GWT.log("Invalid keystroke.");
            event.preventDefault();
        }
    }
}

I then created a regular expression implementation of the ValidationStrategy:

public class RegularExpressionValidationStrategy implements MaskedTextInputCell.ValidationStrategy {
    private String regularExpression;
    public RegularExpressionValidationStrategy(String regularExpression) {
        this.regularExpression = regularExpression;
    }
    @Override
    public boolean matches(String valueToCheck) {
        return valueToCheck.matches(regularExpression);
    }
}

Now, I can do something like this to create a money field:

public class MonetaryTextInputCell extends MaskedTextInputCell {
    public MonetaryTextInputCell() {
        super(new RegularExpressionValidationStrategy("[0-9.]"), 
              new RegularExpressionValidationStrategy("^[0-9.][0-9]*[0-9.]?[0-9]*$"));
    }
}
Community
  • 1
  • 1
Javid Jamae
  • 8,741
  • 4
  • 47
  • 62