diff --git a/packages/main/src/DatePicker.ts b/packages/main/src/DatePicker.ts index a784690f3072..2320aa9df5bd 100644 --- a/packages/main/src/DatePicker.ts +++ b/packages/main/src/DatePicker.ts @@ -59,6 +59,11 @@ type DatePickerChangeEventDetail = { valid: boolean, } +type DatePickerValueStateChangeEventDetail = { + valueState: `${ValueState}`, + valid: boolean, +} + type DatePickerInputEventDetail = { value: string, valid: boolean, @@ -217,6 +222,32 @@ type DatePickerInputEventDetail = { }, }, }) +/** + * Fired before the value state of the component is updated internally. + * The event is preventable, meaning that if it's default action is + * prevented, the component will not update the value state. + * + * @allowPreventDefault + * @public + * @param {string} valueState The new valueState that will be set. + * @param {boolean} valid Indicator if the value is in correct format pattern and in valid range. + */ +@event("value-state-change", { + detail: { + /** + * @public + */ + valueState: { + type: String, + }, + /** + * @public + */ + valid: { + type: Boolean, + }, + }, +}) class DatePicker extends DateComponentBase implements IFormElement { /** * Defines a formatted date value. @@ -542,12 +573,15 @@ class DatePicker extends DateComponentBase implements IFormElement { } _updateValueState() { - const isValid = this._checkValueValidity(this.value); + const valid = this._checkValueValidity(this.value); + const previousValueState = this.valueState; + + this.valueState = valid ? ValueState.None : ValueState.Error; + + const eventPrevented = !this.fireEvent("value-state-change", { valueState: this.valueState, valid }, true); - if (isValid && this.valueState === ValueState.Error) { // If not valid - always set Error regardless of the current value state - this.valueState = ValueState.None; - } else if (!isValid) { // However if valid, change only Error (but not the others) to None - this.valueState = ValueState.Error; + if (eventPrevented) { + this.valueState = previousValueState; } } @@ -860,4 +894,5 @@ export default DatePicker; export type { DatePickerChangeEventDetail, DatePickerInputEventDetail, + DatePickerValueStateChangeEventDetail, }; diff --git a/packages/main/test/pages/DatePicker.html b/packages/main/test/pages/DatePicker.html index 1f1e9f387fa2..70e825dd00df 100644 --- a/packages/main/test/pages/DatePicker.html +++ b/packages/main/test/pages/DatePicker.html @@ -29,6 +29,10 @@
+ +

DatePicker with value-state-change event prevented

+ +

DatePicker with no format pattern & min-max dates in ISO format

@@ -199,6 +203,12 @@

DatePicker with format `yyyy` should open picker on years

dp11.setAttribute("value", dp11.formatValue(new Date(2018, 11, 11))); }); + const datePickerValueStateChangePrevented = document.getElementById("dpVsChangePrevented"); + + datePickerValueStateChangePrevented.addEventListener("value-state-change", function(e) { + e.preventDefault(); + }); + diff --git a/packages/main/test/pages/DatePicker_test_page.html b/packages/main/test/pages/DatePicker_test_page.html index dc5e344a7c20..5017d0dc09c0 100644 --- a/packages/main/test/pages/DatePicker_test_page.html +++ b/packages/main/test/pages/DatePicker_test_page.html @@ -36,6 +36,8 @@ +

DatePicker value-state-change event prevented

+ Set date @@ -102,6 +104,12 @@

Test accessibleName and accessibleNameRef

document.getElementById('b1').addEventListener("click", function(e) { dp16.setAttribute("value", dp16.formatValue(new Date(2018, 11, 11))); }); + + const datePickerValueStateChangePrevented = document.getElementById("dpVsChangePrevented"); + + datePickerValueStateChangePrevented.addEventListener("value-state-change", function(e) { + e.preventDefault(); + }); diff --git a/packages/main/test/specs/DatePicker.spec.js b/packages/main/test/specs/DatePicker.spec.js index 03ab5b1f92a0..e2d55fce74f9 100644 --- a/packages/main/test/specs/DatePicker.spec.js +++ b/packages/main/test/specs/DatePicker.spec.js @@ -1331,4 +1331,18 @@ describe("Date Picker Tests", () => { let displayedYear = await datepicker.getDisplayedYear(11); assert.notOk(await displayedYear.hasClass("ui5-yp-item--disabled"), "Year 2025 is not disabled"); }); + + it("Value state is not changed, when value-state-change is prevented", async () => { + datepicker.id = "#dpVsChangePrevented"; + + const input = await datepicker.getInput(); + + const valueState = await input.getProperty("valueState"); + await input.click(); + await browser.keys("Jan 29, 2019"); + + await browser.$("#dpVsChangePrevented").shadow$("ui5-input").shadow$("input").click(); // click elsewhere to focusout + + assert.strictEqual(await input.getProperty("valueState"), valueState, "value state is not changed"); + }); });