import { createNamespace } from '../utils'; const [createComponent, bem] = createNamespace('form'); export const FORM_KEY = 'vanForm'; export default createComponent({ props: { colon: Boolean, labelWidth: [Number, String], labelAlign: String, inputAlign: String, scrollToError: Boolean, validateFirst: Boolean, errorMessageAlign: String, submitOnEnter: { type: Boolean, default: true, }, validateTrigger: { type: String, default: 'onBlur', }, showError: { type: Boolean, default: true, }, showErrorMessage: { type: Boolean, default: true, }, }, emits: ['submit', 'failed'], provide() { return { [FORM_KEY]: this, }; }, data() { return { children: [], }; }, methods: { validateSeq() { return new Promise((resolve, reject) => { const errors = []; this.children .reduce( (promise, field) => promise.then(() => { if (!errors.length) { return field.validate().then((error) => { if (error) { errors.push(error); } }); } }), Promise.resolve() ) .then(() => { if (errors.length) { reject(errors); } else { resolve(); } }); }); }, validateAll() { return new Promise((resolve, reject) => { Promise.all(this.children.map((item) => item.validate())).then( (errors) => { errors = errors.filter((item) => item); if (errors.length) { reject(errors); } else { resolve(); } } ); }); }, // @exposed-api validate(name) { if (name) { return this.validateField(name); } return this.validateFirst ? this.validateSeq() : this.validateAll(); }, validateField(name) { const matched = this.children.filter((item) => item.props.name === name); if (matched.length) { return new Promise((resolve, reject) => { matched[0].validate().then((error) => { if (error) { reject(error); } else { resolve(); } }); }); } return Promise.reject(); }, // @exposed-api resetValidation(name) { this.children.forEach((item) => { if (!name || item.props.name === name) { item.resetValidation(); } }); }, // @exposed-api scrollToField(name, options) { this.children.some((item) => { if (item.props.name === name) { item.root.value.scrollIntoView(options); return true; } return false; }); }, getValues() { return this.children.reduce((form, field) => { form[field.props.name] = field.formValue; return form; }, {}); }, onSubmit(event) { event.preventDefault(); this.submit(); }, // @exposed-api submit() { const values = this.getValues(); this.validate() .then(() => { this.$emit('submit', values); }) .catch((errors) => { this.$emit('failed', { values, errors, }); if (this.scrollToError) { this.scrollToField(errors[0].name); } }); }, }, render() { return (
{this.$slots.default?.()}
); }, });