Many form-based applications require some sort of data validation for
input controls. It is also often desirable to visualize the validation
state of a control directly in the user interface, for example by
showing a red border to indicate a validation failure.

However, simply validating the current value of a control and
rendering a validation decorator often leads to an undesirable user
experience: for example, in many cases an empty form field shouldn't
indicate a validation failure unless the user has significantly
interacted with the field, or validation was explicitly requested by
pressing a "submit" button.

The first of these validation conditions, "significantly interacted
with the input control" is quite popular on contemporary web forms,
and offers a balanced user experience compared to immediately and
eagerly validating every control, or delaying validation until the
very end of the form submission process (see also the proposed
:user-valid/:user-invalid CSS pseudo-classes).

Unfortunately, this is very hard to implement in JavaFX since controls
have no way of signalling when they were significantly interacted
with. In particular, we don't want to count programmatic
initialization of field values as a significant interaction. What
constitutes a significant interaction is dependent on the type of
input control. For example, a text field might define a significant
interaction as the sequence of gaining focus, receiving a new text
value, and losing focus. A slider might define a significant
interaction as the sequence of pressing the mouse button, dragging the
slider thumb to a new value, and releasing the mouse button.

The information of how an input control changed its value is only
really knowable by its skin and associated behavior classes, both of
which are basically black boxes for a JavaFX application. In order to
expose this information, I propose to add the following new interface
in the "javafx.scene.input" package:

public interface InputNode {
    ReadOnlyBooleanProperty userModifiedProperty();
    boolean isUserModified();
    void setUserModified(boolean value);
}

This interface identifies a node that can receive user input. It is
implemented by the following controls: ButtonBase, ChoiceBox,
ComboBoxBase, Slider, Spinner, and TextInputControl.

The associated skins and behaviors are modified to invoke
setUserModified(true) on the control when a significant user
interaction is detected. Once this flag is set on a control, it can
only be unset programmatically from application code by invoking
setUserModified(false).

You might note that userModifiedProperty() returns
ReadOnlyBooleanProperty, while a public setter is availabe. The reason
for this is that while applications should be able to set or clear the
userModified flag programmatically, they shouldn't be able to bind the
property to prevent it from being set by skins.

Note also that it is not a goal of this proposal to add a data
validation framework to JavaFX (this is best left to third-party
libraries instead). The goal is to expose a crucial piece of
information that is not easily accessible otherwise.

I'm interested on your thoughts on this idea.

Reply via email to