- 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 'element-internals-polyfill'FormElementMixin
export const FormElementMixin = (base) => {
return class Base extends base {
get skipAttributes () {
return [
...super.skipAttributes, 'form'
]
}
get skipProperties () {
return [...super.skipProperties, 'form']
}
/**
* Returning `true` for the formAssociated property allows the element to be
* detected and participate as a form control element in native forms. It is
* also necessary to add the lifecycle hooks related to that behavior.
*/
static get formAssociated () { return true }
static get properties () {
return {
disabled: { type: Boolean },
required: { type: Boolean }
}
}
constructor () {
super()Check if the attachInternals method is available and call it to enable
the ElementInternals API.
if (this.attachInternals) {
this.internals = this.attachInternals()
}
}
firstUpdated () {
super.firstUpdated()
if (this.internals && this.native) {Update form with current value on firstUpdate
this._updateAssociatedForm()
this.native.addEventListener('input', (e) => {Update form value at every input change
this._updateAssociatedForm()
})
}
}
connectedCallback () {
super.connectedCallback()
this._assignFormProperty()
}
_updateAssociatedForm () {
const data = new FormData()
data.append(this.name, this.value)
this.internals.setFormValue(data)
}From web.dev article: The following properties and methods aren’t strictly required, but browser-level form controls provide them. Providing them helps ensure consistency with browser-provided controls.
get form () { return this._assignFormProperty() }
get name () { return this.getAttribute('name') }
get type () { return this.localName }These validity related callbacks are optional, and are already implemented in the NativeValidatorMixin, so we are not going to use the ElementInternals API methods, except for willValidate.
get willValidate () { return this.internals.willValidate }get validity () { return this.internals.validity } get validationMessage () { return this.internals.validationMessage } checkValidity () { console.log(‘check validity called’); return this.internals.checkValidity() } reportValidity () { console.log(‘report validity called’); return this.internals.reportValidity() }
_assignFormProperty () {if (this.tagName === ‘NN-FORM’ || this.tagName === ‘EN-FORM’) return
if (this.internals && this.internals.form) {
return this.internals.form
}
let el = this
while ((el = el.parentElement) && (el.tagName !== 'FORM' && el.tagName !== 'NN-FORM' && el.tagName !== 'EN-FORM' && !el.hasAttribute('as-form'))) { } // eslint-disable-line no-empty
return el
}
}
}