Skip to content

feat: date time picker validation improvements #7346

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

ugur-vaadin
Copy link
Contributor

@ugur-vaadin ugur-vaadin commented Apr 24, 2025

Description

This PR implements DateTimePicker validation improvements for the Flow counterpart. The changes include:

  • Use the new unparsable-change event from the web component
  • Replace the validated event
  • Prevent multiple validations during a single round-trip
  • Improve validation consistency similar to the web component
  • Postpone validation during navigation between DP and TP unless we are certain the value will be invalid (unless it is invalid or out of the range set using mix/max)
  • Introduce a dedicated error message for incomplete values
  • Handle the input element value changes caused by programmatically setting values

Based on the prototype.

Depends on vaadin/web-components#8986.

Part of #6697

Type of change

  • Bugfix
  • Feature

Checklist

  • I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview
  • I have added a description following the guideline.
  • The issue is created in the corresponding repository and I have referenced it.
  • I have added tests to ensure my change is effective and works as intended.
  • New and existing tests are passing locally with my change.
  • I have performed self-review and corrected misspellings.
  • Enhancement / new feature was discussed in a corresponding GitHub issue and Acceptance Criteria were created.

@ugur-vaadin ugur-vaadin force-pushed the feat-datetimepicker-validation-improvements branch from 2a8f775 to 548332e Compare April 24, 2025 20:20
@ugur-vaadin ugur-vaadin marked this pull request as ready for review April 25, 2025 07:07
@ugur-vaadin ugur-vaadin requested review from vursen and yuriy-fix April 25, 2025 07:14
// Notify the server in order to use the formatted values in validation
pendingInputElementValueSyncs++;
getElement().executeJs(
"this.dispatchEvent(new CustomEvent('value-programmatically-set'));");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain why this additional event is necessary? What scenario is it intended to cover?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach might not be correct since isInvalid() will still report true on the server side until the next round-trip occurs. I explored this a bit on my own and may have found a solution that avoids a round-trip: cbd6285. Please let me know if you see any issues with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This solution is quite good overall. Updated the PR based in this approach and applied a few fixes.

@ugur-vaadin ugur-vaadin force-pushed the feat-datetimepicker-validation-improvements branch from 4faeebe to 0fc0548 Compare May 5, 2025 17:58
Comment on lines 520 to 530
@Test
public void setValueProgrammatically_fieldValidatedOnce() {
clickElementWithJs(SET_VALUE_PROGRAMMATICALLY);
assertValidationCount(1);
}

@Test
public void clearAndSetValueProgrammatically_fieldValidatedTwice() {
clickElementWithJs(CLEAR_AND_SET_VALUE_PROGRAMMATICALLY);
assertValidationCount(2);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be tested using unit tests in datetimepicker/validation/BasicValidationTest.java

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from ITs and converted to unit tests.

public void triggerBlurWithNoChange_fieldNotValidated() {
dateInput.sendKeys(Keys.TAB);
timeInput.sendKeys(Keys.TAB);
assertValidationCount(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest combining the tests that assert validity with those that assert the validation count. The validation count should be asserted in every test that verifies validity

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added validation count assertions.

&& value == null
&& (isInputUnparsable() || isInputIncomplete());
synchronizeChildComponentValues(value);
validate(shouldFireValidationStatusChangeEvent);
Copy link
Contributor

@vursen vursen May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Components must be validated before user-defined ValueChangeEvent listeners are triggered to ensure that those listeners have access to the updated invalid state. That's why validate() was originally called inside addValueChangeListener.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the order seems to handle this issue. Added a unit test that should cover this case.

Copy link
Contributor

@vursen vursen May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure... it looks like validation is now running with the previous value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right. The test passing was a coincidence. I reverted the change and replaced change event listener with value change listener.

@@ -327,6 +353,11 @@ public DateTimePicker(LocalDateTime initialDateTime, Locale locale) {
setLocale(locale);
}

private void addValidationListeners() {
getElement().addEventListener("change", e -> validate(true));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling validate(true) on change will result in duplicate validation when using Binder, since Binder already listens to ValueChangeEvent and triggers validation automatically. To prevent similar regressions in the future, each test in BinderValidationIT should assert the validation count.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation count seems to be in line with regular validation in my testing. Can you provide some example cases where the binder validation count is doubled?

@@ -193,7 +211,7 @@ public void setValue_clearValue_assertValidity() {

@Test
public void badInput_changeValue_assertValidity() {
setInputValue(dateInput, "INVALID");
setFieldInvalid();
Copy link
Contributor

@vursen vursen May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use explicit setInputValue calls throughout to avoid potential side-effects and make the test flow more obvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to set the values explicitly.

assertErrorMessage(REQUIRED_ERROR_MESSAGE);
assertServerValid();
assertClientValid();
assertErrorMessage(null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each test case should also assert the validation count.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added count assertions.

@ugur-vaadin ugur-vaadin force-pushed the feat-datetimepicker-validation-improvements branch from 000387f to cb34131 Compare May 7, 2025 11:43
@ugur-vaadin ugur-vaadin force-pushed the feat-datetimepicker-validation-improvements branch from cb34131 to e8df2b8 Compare May 7, 2025 16:40
Copy link

sonarqubecloud bot commented May 7, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants