mirror of
https://github.com/a2nt/webpack-bootstrap-ui-kit.git
synced 2024-10-22 11:05:45 +02:00
IMPR: Add validate form/field functionality
This commit is contained in:
parent
b1952ee184
commit
8f55fa6ef4
64
src/js/ui/validate.field.js
Normal file
64
src/js/ui/validate.field.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import Events from '../_events'
|
||||||
|
const NAME = 'ui.validate.field'
|
||||||
|
|
||||||
|
class ValidateField {
|
||||||
|
#field
|
||||||
|
#extraChecks = []
|
||||||
|
|
||||||
|
constructor(field) {
|
||||||
|
this.#field = field
|
||||||
|
|
||||||
|
// singleton per field
|
||||||
|
if (this.#field.ValidateField) {
|
||||||
|
return this.#field.ValidateField
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#field.ValidateField = this
|
||||||
|
|
||||||
|
// prevent browsers checks (will do it using JS)
|
||||||
|
this.#field.setAttribute('novalidate', 'novalidate')
|
||||||
|
|
||||||
|
this.#field.addEventListener('change', this.validate)
|
||||||
|
this.#field.addEventListener('focusout', this.validate)
|
||||||
|
|
||||||
|
this.#field.classList.add(`${NAME}--active`)
|
||||||
|
this.#field.dispatchEvent(new Event(Events.FORM_INIT_VALIDATE_FIELD))
|
||||||
|
}
|
||||||
|
|
||||||
|
addExtraCheck = (func) => {
|
||||||
|
this.#extraChecks.push(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
validate = () => {
|
||||||
|
// browser check
|
||||||
|
if (!this.#field.checkValidity()) {
|
||||||
|
console.warn(`${NAME}: ${this.#field.getAttribute('name')} validation failed`)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// run extra checks
|
||||||
|
let valid = true
|
||||||
|
for (const func in this.#extraChecks) {
|
||||||
|
valid = func(this.#field)
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
destruct = () => {
|
||||||
|
this.#field.removeAttribute('novalidate')
|
||||||
|
this.#field.removeEventListener('change', this.validate)
|
||||||
|
this.#field.removeEventListener('focusout', this.validate)
|
||||||
|
|
||||||
|
this.#field.ValidateField = null
|
||||||
|
|
||||||
|
this.#field.classList.remove(`${NAME}--active`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ValidateField
|
122
src/js/ui/validate.form.js
Normal file
122
src/js/ui/validate.form.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import Events from '../_events'
|
||||||
|
import ValidateField from './validate.field'
|
||||||
|
|
||||||
|
const NAME = 'ui.validate.form'
|
||||||
|
|
||||||
|
class ValidateForm {
|
||||||
|
#steppedUI
|
||||||
|
#form
|
||||||
|
#extraChecks = []
|
||||||
|
|
||||||
|
constructor(form) {
|
||||||
|
this.#form = form
|
||||||
|
|
||||||
|
// singleton per form
|
||||||
|
if (this.#form.ValidateForm) {
|
||||||
|
return this.#form.ValidateForm
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#form.ValidateForm = this
|
||||||
|
|
||||||
|
console.log(`${NAME}: init`)
|
||||||
|
// prevent browsers checks (will do it using JS)
|
||||||
|
this.#form.setAttribute('novalidate', 'novalidate')
|
||||||
|
|
||||||
|
// link extra UI API
|
||||||
|
this.#form.addEventListener(`${Events.FORM_INIT_STEPPED}`, this.setStepFormUI)
|
||||||
|
|
||||||
|
// init fields validation
|
||||||
|
const fields = this.getFields()
|
||||||
|
fields.forEach((field) => {
|
||||||
|
new ValidateField(field)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#form.addEventListener('submit', this.submitHandler)
|
||||||
|
|
||||||
|
this.#form.classList.add(`${NAME}--active`)
|
||||||
|
this.#form.dispatchEvent(new Event(Events.FORM_INIT_VALIDATE))
|
||||||
|
}
|
||||||
|
|
||||||
|
getFields = () => {
|
||||||
|
return this.#form.querySelectorAll('input,textarea,select')
|
||||||
|
}
|
||||||
|
|
||||||
|
submitHandler = async () => {
|
||||||
|
console.log(`${NAME}: submitHandler`)
|
||||||
|
const valid = await this.validate()
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
const alert = form.querySelector('.error,.alert-error')
|
||||||
|
|
||||||
|
if (alert) {
|
||||||
|
alert.scrollIntoView();
|
||||||
|
this.#form.dispatchEvent(new Event(Events.FORM_VALIDATION_FAILED))
|
||||||
|
|
||||||
|
// switch to step
|
||||||
|
if (this.#steppedUI) {
|
||||||
|
this.#steppedUI.step(alert.closest('.step'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addExtraCheck = (func) => {
|
||||||
|
this.#extraChecks.push(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
validate = async () => {
|
||||||
|
let valid = true
|
||||||
|
const fields = this.#form.querySelectorAll('input,textarea,select')
|
||||||
|
|
||||||
|
// check fields
|
||||||
|
for (const field of fields) {
|
||||||
|
if (field.ValidateField) {
|
||||||
|
valid = await field.ValidateField.validate()
|
||||||
|
if (!valid) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// run extra checks
|
||||||
|
for (const func in this.#extraChecks) {
|
||||||
|
valid = func(this.#form)
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
setStepFormUI = () => {
|
||||||
|
this.#steppedUI = this.#form.steppedForm
|
||||||
|
}
|
||||||
|
|
||||||
|
destruct = () => {
|
||||||
|
console.log(`${NAME}: destruct`)
|
||||||
|
|
||||||
|
this.#form.removeAttribute('novalidate')
|
||||||
|
this.#form.removeEventListener(`${Events.FORM_INIT_STEPPED}`, this.setStepFormUI)
|
||||||
|
|
||||||
|
// remove fields validation
|
||||||
|
const fields = this.getFields()
|
||||||
|
fields.forEach((field) => {
|
||||||
|
if (field.ValidateField) {
|
||||||
|
field.ValidateField.destruct()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.#form.removeEventListener('submit', this.submitHandler)
|
||||||
|
|
||||||
|
this.#form.ValidateForm = null
|
||||||
|
this.#form.classList.remove(`${NAME}--active`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ValidateForm
|
Loading…
Reference in New Issue
Block a user