Skip to content
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

Fix: Prioritize component validation over native validation #885

Merged
67 changes: 48 additions & 19 deletions packages/uui-base/lib/mixins/FormControlMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,25 @@ type FlagTypes =
| 'badInput'
| 'valid';

const WeightedErrorFlagTypes = [
'customError',
'valueMissing',
'badInput',
'typeMismatch',
'patternMismatch',
'rangeOverflow',
'rangeUnderflow',
'stepMismatch',
'tooLong',
'tooShort',
];

// Acceptable as an internal interface/type, BUT if exposed externally this should be turned into a public class in a separate file.
interface UUIFormControlValidatorConfig {
flagKey: FlagTypes;
getMessageMethod: () => string;
checkMethod: () => boolean;
weight: number;
}

export interface UUIFormControlMixinInterface<ValueType> extends LitElement {
Expand Down Expand Up @@ -294,13 +308,18 @@ export const UUIFormControlMixin = <
getMessageMethod: () => string,
checkMethod: () => boolean,
): UUIFormControlValidatorConfig {
const obj = {
const validator = {
flagKey: flagKey,
getMessageMethod: getMessageMethod,
checkMethod: checkMethod,
weight: WeightedErrorFlagTypes.indexOf(flagKey),
};
this.#validators.push(obj);
return obj;
this.#validators.push(validator);
// Sort validators based on the WeightedErrorFlagTypes order. [NL]
this.#validators.sort((a, b) =>
a.weight > b.weight ? 1 : b.weight > a.weight ? -1 : 0,
);
return validator;
}

protected removeValidator(validator: UUIFormControlValidatorConfig) {
Expand Down Expand Up @@ -365,29 +384,38 @@ export const UUIFormControlMixin = <
*/
protected _runValidators() {
this.#validity = {};
const messages: Set<string> = new Set();
//const messages: Set<string> = new Set();
let message: string | undefined = undefined;
let innerFormControlEl: NativeFormControlElement | undefined = undefined;

// Loop through inner native form controls to adapt their validityState. [NL]
this.#formCtrlElements.forEach(formCtrlEl => {
let key: keyof ValidityState;
for (key in formCtrlEl.validity) {
if (key !== 'valid' && formCtrlEl.validity[key]) {
this.#validity[key] = true;
messages.add(formCtrlEl.validationMessage);
innerFormControlEl ??= formCtrlEl;
}
}
});

// Loop through custom validators, currently its intentional to have them overwritten native validity. but might need to be reconsidered (This current way enables to overwrite with custom messages) [NL]
this.#validators.forEach(validator => {
this.#validators.some(validator => {
if (validator.checkMethod()) {
this.#validity[validator.flagKey] = true;
messages.add(validator.getMessageMethod());
//messages.add(validator.getMessageMethod());
message = validator.getMessageMethod();
return true;
}
return false;
});

if (!message) {
// Loop through inner native form controls to adapt their validityState. [NL]
this.#formCtrlElements.some(formCtrlEl => {
let key: keyof ValidityState;
for (key in formCtrlEl.validity) {
if (key !== 'valid' && formCtrlEl.validity[key]) {
this.#validity[key] = true;
//messages.add(formCtrlEl.validationMessage);
message = formCtrlEl.validationMessage;
innerFormControlEl ??= formCtrlEl;
return true;
}
}
return false;
});
}

const hasError = Object.values(this.#validity).includes(true);

// https://developer.mozilla.org/en-US/docs/Web/API/ValidityState#valid
Expand All @@ -397,7 +425,8 @@ export const UUIFormControlMixin = <
this._internals.setValidity(
this.#validity,
// Turn messages into an array and join them with a comma. [NL]:
[...messages].join(', '),
//[...messages].join(', '),
message,
innerFormControlEl ?? this.getFormElement() ?? undefined,
);

Expand Down
4 changes: 4 additions & 0 deletions packages/uui-boolean-input/lib/uui-boolean-input.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,10 @@ export abstract class UUIBooleanInputElement extends UUIFormControlMixin(
cursor: not-allowed;
opacity: 0.5;
}

.label {
display: block;
}
`,
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ export class UUIFormValidationMessageElement extends LitElement {
} else {
this._messages.delete(ctrl);
}
this.requestUpdate();
this.requestUpdate('_messages');
};

private _onControlValid = (e: UUIFormControlEvent) => {
const ctrl = (e as any).composedPath()[0];
this._messages.delete(ctrl);
this.requestUpdate();
this.requestUpdate('_messages');
};

render() {
Expand Down
Loading