- index
- quickstart designers
- tutorials designers
- quickstart developers
- tutorials developers
- elements
- mixins
- AddHasValueAttributeMixin.js
- DraggableElementMixin.js
- DraggableListMixin.js
- FormElementMixin.js
- InputMixin.js
- LabelsMixin.js
- NativeReflectorMixin.js
- NativeValidatorMixin.js
- StyleableMixin.js
- SyntheticValidatorMixin.js
- ThemeableMixin.js
- appendices
- material theme
import { html, css } from 'lit'
export const NativeValidatorMixin = (base) => {
return class Base extends base {
static get properties () {
return {
nativeErrorMessages: {
type: Boolean,
attribute: 'native-error-messages'
},
shownValidationMessage: {
type: String,
attribute: false
},
validator: { type: Function },
validationMessages: {
type: Object,
attribute: 'validition-messages'
},
validationMessagePosition: {
type: String,
attribute: 'validation-message-position'
}
}
}
static get styles () {
return [
super.styles || [],
css`
span.error-message {
color: red;
}
:invalid {
background-color: pink;
border: var(--native-validator-mixin-input-border-invalid, 1px solid #bb7777);
}
`
]
}
constructor () {
super()
this.validator = () => ''
this.nativeValidationKeys = [
'badInput',
'customError',
'patternMismatch',
'rangeOverflow',
'rangeUnderflow',
'stepMismatch',
'valueMissing',
'tooLong',
'tooShort',
'typeMismatch'
]
this.validationMessages = {}
this.validationMessagePosition = 'before'
this._showPrettyError = false
}
get skipProperties () {
return [...super.skipProperties, 'checkValidity', 'reportValidity', 'setCustomValidity']
}
get validationMessageTemplate () {
return html`
<span class="error-message">
${this.shownValidationMessage}
</span>
`
}
get ifValidationMessageBefore () {
if (this.validationMessagePosition === 'after') return ''
return this.validationMessageTemplate
}
get ifValidationMessageAfter () {
if (this.validationMessagePosition === 'before') return ''
return this.validationMessageTemplate
}
setCustomValidity (m) {
if (!this.native) return
return this.native.setCustomValidity(m)
}
_runValidator () {Call the validator with a value. Here an element could be a checkbox, a select, an simple text input, etc. If the containing form has _getElementValueSource, that is used to figure out what to pass to the validato (as well as _submitObject)
let value
let submitObject
if (this.form && this.form._getElementValueSource) {
value = this[this.form._getElementValueSource(this)]
submitObject = this.form.submitObject
}
const ownErrorMessage = this.validator(value, submitObject)
if (ownErrorMessage) this.setCustomValidity(ownErrorMessage)
}
reportValidity () {
if (!this.native) return trueRun custom validator. Note that custom validator will only ever run on filed without an existing customError.
if (!this.native.validity.customError) {
this._runValidator()
}Hide the fancy error message by default
this.shownValidationMessage = ''Run reportValidity which will display the native error messages. Suppress the pretty error messages
if (this.nativeErrorMessages) {
this._showPrettyError = false
return this.native.reportValidity()
} else {Since pretty errors will be shown, it will actually return checkValidity() which will not show the error messages
this._showPrettyError = true
return this.native.checkValidity()
}
}
checkValidity () {
if (!this.native) return trueRun custom validator. Note that custom validator will only ever run on filed without an existing customError.
if (!this.native.validity.customError) {
this._runValidator()
}
this._showPrettyError = false
return this.native.checkValidity()
}
firstUpdated () {
super.firstUpdated()
this.native.oninput = (e) => {
this.setCustomValidity('')
this.reportValidity()
}
this.native.oninvalid = (e) => {No pretty error to be shown (probably running checkValidity())
if (!this._showPrettyError) return
const validity = e.target.validityFind which one flag in validity is raised
let found
for (const k of this.nativeValidationKeys) {
if (validity[k]) {
found = k
break
}
}Assign shownValidationMessage Allow translating with specific function
const translator = this.validationMessages[found]
if (translator) {
this.shownValidationMessage = (typeof translator === 'function')
? translator(e.target.validationMessage)
: translator
} else {
this.shownValidationMessage = e.target.validationMessage
}
}
}
}
}