Skip to content

pat validation: also check depending date #971

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

Merged
merged 2 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions src/pat/tabs/tabs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,19 @@ describe("pat-tabs", function () {
el.innerHTML = "<div></div>";
jest.spyOn(el, "getBoundingClientRect").mockImplementation(() => { return { x: 0, width: 0 }; }); // prettier-ignore

pattern.init(el.querySelector("div"));
await utils.timeout(1);
document.body.dispatchEvent(new Event("pat-update"));
expect(pattern).not.toThrow(TypeError);
let thrown = false;
try {
pattern.init(el.querySelector("div"));
await utils.timeout(1);
document.body.dispatchEvent(new Event("pat-update"));
await utils.timeout(1);
} catch (e) {
if (e instanceof TypeError) {
thrown = true;
} else {
throw e;
}
}
expect(thrown).toBe(false);
});
});
31 changes: 19 additions & 12 deletions src/pat/validation/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export default Base.extend({
for (const [cnt, input] of this.inputs.entries()) {
// Cancelable debouncer.
const debouncer = utils.debounce((e) => {
this.check_input(input, e);
this.check_input({ input: input, event: e });
}, this.options.delay);

events.add_event_listener(
Expand All @@ -82,12 +82,12 @@ export default Base.extend({
this.el,
"submit",
`pat-validation--blur-${input.name}--${cnt}--validator`,
(e) => this.check_input(input, e) // immediate check with submit. Otherwise submit is not cancelable.
(e) => this.check_input({ input: input, event: e }) // immediate check with submit. Otherwise submit is not cancelable.
);
}
},

check_input(input, e) {
check_input({ input, event, stop = false }) {
if (input.disabled) {
// No need to check disabled inputs.
return;
Expand All @@ -97,7 +97,7 @@ export default Base.extend({
this.set_validity({ input: input, msg: "" });
const validity_state = input.validity;

if (e.submitter?.hasAttribute("formnovalidate")) {
if (event?.submitter?.hasAttribute("formnovalidate")) {
// Do not submit when a button with ``formnovalidate`` was used.
return;
}
Expand Down Expand Up @@ -139,6 +139,8 @@ export default Base.extend({

let not_after;
let not_before;
let not_after_el;
let not_before_el;
const date = new Date(input.value);
if (isNaN(date)) {
// Should not happen or input only partially typed in.
Expand All @@ -149,9 +151,8 @@ export default Base.extend({
not_after = new Date(input_options.not.after);
if (isNaN(not_after)) {
// Handle value as selector
not_after = document.querySelector(
input_options.not.after
)?.value;
not_after_el = document.querySelector(input_options.not.after);
not_after = not_after_el?.value;
not_after =
not_after &&
new Date(
Expand All @@ -167,9 +168,8 @@ export default Base.extend({
not_before = new Date(input_options.not.before);
if (isNaN(not_before)) {
// Handle value as selector
not_before = document.querySelector(
input_options.not.before
)?.value;
not_before_el = document.querySelector(input_options.not.before);
not_before = not_before_el?.value;
not_before =
not_before &&
new Date(
Expand All @@ -185,6 +185,13 @@ export default Base.extend({
} else if (not_before && date < not_before) {
this.set_validity({ input: input, msg: msg });
}
// always check the other input to clear/set errors
!stop && // do not re-check when stop is set to avoid infinite loops
not_after_el &&
this.check_input({ input: not_after_el, stop: true });
!stop &&
not_before_el &&
this.check_input({ input: not_before_el, stop: true });
}

if (!validity_state.customError) {
Expand Down Expand Up @@ -248,9 +255,9 @@ export default Base.extend({
}
}

if (e.type === "submit") {
if (event?.type === "submit") {
// Do not submit in error case.
e.preventDefault();
event.preventDefault();
}
this.set_error_message(input, input_options);
},
Expand Down
42 changes: 24 additions & 18 deletions src/pat/validation/validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -824,15 +824,6 @@ describe("pat-validation", function () {
inp_end.value = "2020-10-05";
inp_end.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(1);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The end date must on or before the start date."
);

// Violate the before/after constraint
inp_start.value = "2020-10-06";
inp_start.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(2);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The start date must on or before the end date."
Expand All @@ -849,6 +840,18 @@ describe("pat-validation", function () {
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(0);

// Violate the before/after constraint
inp_start.value = "2020-10-11";
inp_start.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(2);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The start date must on or before the end date."
);
expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
"The end date must on or before the start date."
);

// Fulfill the before/after constraint - start before end
inp_start.value = "2020-10-01";
inp_start.dispatchEvent(events.change_event());
Expand Down Expand Up @@ -947,15 +950,6 @@ describe("pat-validation", function () {
inp_end.value = "2022-01-05T09:00";
inp_end.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(1);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The end date/time must on or before the start date/time."
);

// Violate the before/after constraint
inp_start.value = "2022-01-05T11:00";
inp_start.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(2);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The start date/time must on or before the end date/time."
Expand All @@ -972,6 +966,18 @@ describe("pat-validation", function () {
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(0);

// Violate the before/after constraint
inp_start.value = "2022-01-05T11:00";
inp_start.dispatchEvent(events.change_event());
await utils.timeout(1); // wait a tick for async to settle.
expect(el.querySelectorAll("em.warning").length).toBe(2);
expect(el.querySelectorAll("em.warning")[0].textContent).toBe(
"The start date/time must on or before the end date/time."
);
expect(el.querySelectorAll("em.warning")[1].textContent).toBe(
"The end date/time must on or before the start date/time."
);

// Fulfill the before/after constraint - start before end
inp_start.value = "2022-01-04T10:00";
inp_start.dispatchEvent(events.change_event());
Expand Down