1
0
mirror of synced 2024-11-29 08:36:12 +03:00
vue-formulario/src~v1/components/Formulate.vue
2019-10-07 10:24:30 -04:00

182 lines
4.8 KiB
Vue

<template>
<form
@submit.prevent="submit"
class="formulate-form"
>
<slot />
</form>
</template>
<script>
import {equals, reduce} from '../utils'
import cloneDeep from 'clone-deep'
export default {
props: {
name: {
type: String,
required: true
},
module: {
type: [String, Boolean],
default: function () {
return this.$formulate.options.vuexModule
}
},
initial: {
type: Object,
default: () => ({})
},
behavior: {
type: String,
default: 'blur'
},
showErrors: {
type: [Boolean, Object],
default: () => ({})
},
errors: {
type: Object,
default: () => ({})
},
prevent: {
type: String,
default: 'validation'
}
},
data () {
return {
parentIdentifier: 'vue-formulate-wrapper-element',
forceErrors: null,
fieldInitials: {},
whenFinishedValidating: Promise.resolve()
}
},
computed: {
m () {
return `${this.module ? this.module + '/' : ''}`
},
hasErrors () {
return this.$store.getters[`${this.m}hasErrors`][this.name] || false
},
hasValidationErrors () {
return this.$store.getters[`${this.m}hasValidationErrors`][this.name] || false
},
values () {
return cloneDeep(this.$store.getters[`${this.m}formValues`][this.name] || {})
},
storeErrors () {
return this.$store.getters[`${this.m}formErrors`][this.name] || {}
},
validationErrors () {
return this.$store.getters[`${this.m}formValidationErrors`][this.name] || {}
},
fields () {
return this.$store.getters[`${this.m}formMeta`][this.name] || []
},
shouldShowErrors () {
if (this.forceErrors === false || this.forceErrors === true) {
return this.forceErrors
}
if (this.showErrors === false || this.showErrors === true) {
return this.showErrors
}
return this.behavior === 'live'
},
mergedInitial () {
return Object.assign({}, this.initial, this.fieldInitials)
}
},
watch: {
mergedInitial () {
this.hydrate(this.mergedInitial)
},
values () {
this.updateFormValidation()
}
},
created () {
this.hydrate(this.mergedInitial)
},
mounted () {
this.hydrate(this.mergedInitial)
},
methods: {
registerField (field, data) {
this.$store.commit(`${this.m}setFieldMeta`, {form: this.name, field, data})
if (data.type !== 'submit') {
this.$store.commit(`${this.m}setFieldValue`, {
field,
value: this.mergedInitial.hasOwnProperty(field) ? this.mergedInitial[field] : undefined,
form: this.name
})
}
},
async deregisterField (field) {
await this.whenFinishedValidating
this.$store.commit(`${this.m}removeField`, {
form: this.name,
field
})
},
hydrate (values) {
for (let field of this.fields) {
if (field.type !== 'submit' && typeof this.values[field.name] === 'undefined') {
this.$store.commit(`${this.m}setFieldValue`, {
field: field.name,
value: values[field.name],
form: this.name
})
}
}
},
setInitial (field, value) {
this.fieldInitials = Object.assign({}, this.fieldInitials, {[field]: value})
},
update (change) {
this.$store.commit(`${this.m}setFieldValue`, Object.assign(change, {
form: this.name
}))
},
updateFieldErrors (change) {
this.$store.commit(`${this.m}setFieldErrors`, Object.assign(change, {
form: this.name
}))
},
updateFieldValidationErrors (change) {
this.$store.commit(`${this.m}setFieldValidationErrors`, Object.assign(change, {
form: this.name
}))
},
async validateField ({field, validation, label}) {
let errors = await this.$formulate.validationErrors({
field,
value: this.values[field],
label
}, validation, this.values)
if (!equals(errors || [], (this.validationErrors[field] || []))) {
if (this.fields.find(f => f.name === field)) {
this.updateFieldValidationErrors({field, errors: errors || []})
}
}
return errors
},
async updateFormValidation () {
await this.whenFinishedValidating
this.whenFinishedValidating = Promise.all(this.fields.map(async field => this.validateField({
field: field.name,
validation: field.validation,
label: field.validationLabel || field.label || field.name
})))
},
submit () {
if ((this.prevent === 'validation' && this.hasValidationErrors) || (this.prevent === 'any' && this.hasErrors)) {
this.forceErrors = true
} else {
this.$emit('submit', Object.assign({}, this.values))
}
}
}
}
</script>