Skip to content

Commit

Permalink
fix(select,textfield): native form validation shows error state
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 578632986
  • Loading branch information
Elliott Marquez authored and copybara-github committed Nov 1, 2023
1 parent 87dfee4 commit 6b5ab21
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
37 changes: 36 additions & 1 deletion select/internal/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ export abstract class Select extends selectBaseClass {
@query('#label') private readonly labelEl!: HTMLElement;
@queryAssignedElements({slot: 'leading-icon', flatten: true})
private readonly leadingIcons!: Element[];
private isCheckingValidity = false;
private isReportingValidity = false;
private customValidationMessage = '';

/**
Expand Down Expand Up @@ -304,8 +306,11 @@ export abstract class Select extends selectBaseClass {
* @return true if the select is valid, or false if not.
*/
checkValidity() {
this.isCheckingValidity = true;
this.syncValidity();
return this[internals].checkValidity();
const isValid = this[internals].checkValidity();
this.isCheckingValidity = false;
return isValid;
}

/**
Expand All @@ -325,6 +330,7 @@ export abstract class Select extends selectBaseClass {
* @return true if the select is valid, or false if not.
*/
reportValidity() {
this.isReportingValidity = true;
let invalidEvent: Event | undefined;
this.addEventListener(
'invalid',
Expand All @@ -335,6 +341,14 @@ export abstract class Select extends selectBaseClass {
);

const valid = this.checkValidity();
this.showErrorMessage(valid, invalidEvent);

this.isReportingValidity = false;

return valid;
}

private showErrorMessage(valid: boolean, invalidEvent: Event | undefined) {
if (invalidEvent?.defaultPrevented) {
return valid;
}
Expand Down Expand Up @@ -836,6 +850,27 @@ export abstract class Select extends selectBaseClass {
return select.validationMessage;
}

private readonly onInvalid = (invalidEvent: Event) => {
if (this.isCheckingValidity || this.isReportingValidity) {
return;
}

this.showErrorMessage(false, invalidEvent);
};

override connectedCallback() {
super.connectedCallback();

// Handles the case where the user submits the form and native validation
// error pops up. We want the error styles to show.
this.addEventListener('invalid', this.onInvalid);
}

override disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('invalid', this.onInvalid);
}

// Writable mixin properties for lit-html binding, needed for lit-analyzer
declare disabled: boolean;
declare name: string;
Expand Down
36 changes: 35 additions & 1 deletion textfield/internal/text-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@ export abstract class TextField extends textFieldBaseClass {
private readonly leadingIcons!: Element[];
@queryAssignedElements({slot: 'trailing-icon'})
private readonly trailingIcons!: Element[];
private isCheckingValidity = false;
private isReportingValidity = false;
// Needed for Safari, see https://bugs.webkit.org/show_bug.cgi?id=261432
// Replace with this[internals].validity.customError when resolved.
private hasCustomValidityError = false;
Expand All @@ -402,8 +404,11 @@ export abstract class TextField extends textFieldBaseClass {
* @return true if the text field is valid, or false if not.
*/
checkValidity() {
this.isCheckingValidity = true;
this.syncValidity();
return this[internals].checkValidity();
const isValid = this[internals].checkValidity();
this.isCheckingValidity = false;
return isValid;
}

/**
Expand All @@ -425,6 +430,7 @@ export abstract class TextField extends textFieldBaseClass {
* @return true if the text field is valid, or false if not.
*/
reportValidity() {
this.isReportingValidity = true;
let invalidEvent: Event | undefined;
this.addEventListener(
'invalid',
Expand All @@ -435,6 +441,14 @@ export abstract class TextField extends textFieldBaseClass {
);

const valid = this.checkValidity();
this.showErrorMessage(valid, invalidEvent);

this.isReportingValidity = false;

return valid;
}

private showErrorMessage(valid: boolean, invalidEvent: Event | undefined) {
if (invalidEvent?.defaultPrevented) {
return valid;
}
Expand Down Expand Up @@ -825,6 +839,26 @@ export abstract class TextField extends textFieldBaseClass {
this.hasTrailingIcon = this.trailingIcons.length > 0;
}

private readonly onInvalid = (invalidEvent: Event) => {
if (this.isCheckingValidity || this.isReportingValidity) {
return;
}

this.showErrorMessage(false, invalidEvent);
};

override connectedCallback() {
super.connectedCallback();

// Handles the case where the user submits the form and native validation
// error pops up. We want the error styles to show.
this.addEventListener('invalid', this.onInvalid);
}

override disconnectedCallback() {
super.disconnectedCallback();
this.removeEventListener('invalid', this.onInvalid);
}
// Writable mixin properties for lit-html binding, needed for lit-analyzer
declare disabled: boolean;
declare name: string;
Expand Down

0 comments on commit 6b5ab21

Please sign in to comment.