ant-design-vue/components/form-model/Form.jsx
2020-07-06 22:31:07 +08:00

188 lines
5.5 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { inject, provide } from 'vue';
import PropTypes from '../_util/vue-types';
import classNames from 'classnames';
import { ColProps } from '../grid/Col';
import isRegExp from 'lodash/isRegExp';
import warning from '../_util/warning';
import FormItem from './FormItem';
import { initDefaultProps, getListeners, getSlot } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
export const FormProps = {
layout: PropTypes.oneOf(['horizontal', 'inline', 'vertical']),
labelCol: PropTypes.shape(ColProps).loose,
wrapperCol: PropTypes.shape(ColProps).loose,
colon: PropTypes.bool,
labelAlign: PropTypes.oneOf(['left', 'right']),
prefixCls: PropTypes.string,
hideRequiredMark: PropTypes.bool,
model: PropTypes.object,
rules: PropTypes.object,
validateMessages: PropTypes.any,
validateOnRuleChange: PropTypes.bool,
};
export const ValidationRule = {
/** validation error message */
message: PropTypes.string,
/** built-in validation type, available options: https://github.com/yiminghe/async-validator#type */
type: PropTypes.string,
/** indicates whether field is required */
required: PropTypes.boolean,
/** treat required fields that only contain whitespace as errors */
whitespace: PropTypes.boolean,
/** validate the exact length of a field */
len: PropTypes.number,
/** validate the min length of a field */
min: PropTypes.number,
/** validate the max length of a field */
max: PropTypes.number,
/** validate the value from a list of possible values */
enum: PropTypes.oneOfType([String, PropTypes.arrayOf(String)]),
/** validate from a regular expression */
pattern: PropTypes.custom(isRegExp),
/** transform a value before validation */
transform: PropTypes.func,
/** custom validate function (Note: callback must be called) */
validator: PropTypes.func,
};
const Form = {
name: 'AFormModel',
inheritAttrs: false,
props: initDefaultProps(FormProps, {
layout: 'horizontal',
hideRequiredMark: false,
colon: true,
}),
Item: FormItem,
created() {
this.fields = [];
this.form = undefined;
provide('FormContext', this);
},
setup() {
return {
configProvider: inject('configProvider', ConfigConsumerProps),
};
},
watch: {
rules() {
if (this.validateOnRuleChange) {
this.validate(() => {});
}
},
},
computed: {
vertical() {
return this.layout === 'vertical';
},
},
methods: {
addField(field) {
if (field) {
this.fields.push(field);
}
},
removeField(field) {
if (field.prop) {
this.fields.splice(this.fields.indexOf(field), 1);
}
},
onSubmit(e) {
if (!getListeners(this).submit) {
e.preventDefault();
} else {
this.$emit('submit', e);
}
},
resetFields() {
if (!this.model) {
warning(false, 'FormModel', 'model is required for resetFields to work.');
return;
}
this.fields.forEach(field => {
field.resetField();
});
},
clearValidate(props = []) {
const fields = props.length
? typeof props === 'string'
? this.fields.filter(field => props === field.prop)
: this.fields.filter(field => props.indexOf(field.prop) > -1)
: this.fields;
fields.forEach(field => {
field.clearValidate();
});
},
validate(callback) {
if (!this.model) {
warning(false, 'FormModel', 'model is required for resetFields to work.');
return;
}
let promise;
// if no callback, return promise
if (typeof callback !== 'function' && window.Promise) {
promise = new window.Promise((resolve, reject) => {
callback = function(valid) {
valid ? resolve(valid) : reject(valid);
};
});
}
let valid = true;
let count = 0;
// 如果需要验证的fields为空调用验证时立刻返回callback
if (this.fields.length === 0 && callback) {
callback(true);
}
let invalidFields = {};
this.fields.forEach(field => {
field.validate('', (message, field) => {
if (message) {
valid = false;
}
invalidFields = Object.assign({}, invalidFields, field);
if (typeof callback === 'function' && ++count === this.fields.length) {
callback(valid, invalidFields);
}
});
});
if (promise) {
return promise;
}
},
validateField(props, cb) {
props = [].concat(props);
const fields = this.fields.filter(field => props.indexOf(field.prop) !== -1);
if (!fields.length) {
warning(false, 'FormModel', 'please pass correct props!');
return;
}
fields.forEach(field => {
field.validate('', cb);
});
},
},
render() {
const { prefixCls: customizePrefixCls, hideRequiredMark, layout, onSubmit } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('form', customizePrefixCls);
const { class: className, onSubmit: originSubmit, ...restProps } = this.$attrs;
const formClassName = classNames(prefixCls, className, {
[`${prefixCls}-horizontal`]: layout === 'horizontal',
[`${prefixCls}-vertical`]: layout === 'vertical',
[`${prefixCls}-inline`]: layout === 'inline',
[`${prefixCls}-hide-required-mark`]: hideRequiredMark,
});
return (
<form onSubmit={onSubmit} class={formClassName} {...restProps}>
{getSlot(this)}
</form>
);
},
};
export default Form;