ant-design-vue/components/vc-form/src/createBaseForm.jsx

680 lines
22 KiB
Vue
Raw Normal View History

2019-01-12 03:33:27 +00:00
import AsyncValidator from 'async-validator';
import warning from 'warning';
import get from 'lodash/get';
import set from 'lodash/set';
import omit from 'lodash/omit';
import createFieldsStore from './createFieldsStore';
import { cloneElement } from '../../_util/vnode';
import BaseMixin from '../../_util/BaseMixin';
import { getOptionProps, getEvents } from '../../_util/props-util';
import PropTypes from '../../_util/vue-types';
2018-05-04 04:16:17 +00:00
2018-05-02 13:35:42 +00:00
import {
argumentContainer,
identity,
normalizeValidateRules,
getValidateTriggers,
getValueFromEvent,
hasRules,
getParams,
isEmptyObject,
flattenArray,
2019-01-12 03:33:27 +00:00
} from './utils';
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
const DEFAULT_TRIGGER = 'change';
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
function createBaseForm(option = {}, mixins = []) {
2018-05-02 13:35:42 +00:00
const {
validateMessages,
onFieldsChange,
onValuesChange,
mapProps = identity,
mapPropsToFields,
fieldNameProp,
fieldMetaProp,
fieldDataProp,
formPropName = 'form',
2019-01-01 08:25:50 +00:00
name: formName,
2018-05-06 10:32:40 +00:00
props = {},
2018-06-23 09:17:45 +00:00
templateContext,
2019-01-12 03:33:27 +00:00
} = option;
return function decorate(WrappedComponent) {
let formProps = {};
2018-05-06 10:32:40 +00:00
if (Array.isArray(props)) {
2019-01-12 03:33:27 +00:00
props.forEach(prop => {
formProps[prop] = PropTypes.any;
});
2018-05-06 10:32:40 +00:00
} else {
2019-01-12 03:33:27 +00:00
formProps = props;
2018-05-06 10:32:40 +00:00
}
2018-05-03 11:10:43 +00:00
const Form = {
mixins: [BaseMixin, ...mixins],
2018-05-06 10:32:40 +00:00
props: {
...formProps,
wrappedComponentRef: PropTypes.func.def(() => {}),
},
2019-01-12 03:33:27 +00:00
data() {
const fields = mapPropsToFields && mapPropsToFields(this.$props);
this.fieldsStore = createFieldsStore(fields || {});
this.templateContext = templateContext;
2019-01-12 03:33:27 +00:00
this.instances = {};
this.cachedBind = {};
this.clearedFieldMetaCache = {};
2018-10-31 13:39:12 +00:00
2019-01-12 03:33:27 +00:00
this.renderFields = {};
2018-10-31 13:39:12 +00:00
this.domFields = {};
2018-05-02 13:35:42 +00:00
// HACK: https://github.com/ant-design/ant-design/issues/6406
2019-01-12 03:33:27 +00:00
[
'getFieldsValue',
2018-05-02 13:35:42 +00:00
'getFieldValue',
'setFieldsInitialValue',
'getFieldsError',
'getFieldError',
'isFieldValidating',
'isFieldsValidating',
'isFieldsTouched',
2019-01-12 03:33:27 +00:00
'isFieldTouched',
].forEach(key => {
2018-05-02 13:35:42 +00:00
this[key] = (...args) => {
2019-01-12 03:33:27 +00:00
return this.fieldsStore[key](...args);
};
});
2018-05-02 13:35:42 +00:00
return {
submitting: false,
2019-01-12 03:33:27 +00:00
};
2018-05-02 13:35:42 +00:00
},
2019-01-12 03:33:27 +00:00
watch: templateContext
? {}
: {
$props: {
handler: function(nextProps) {
if (mapPropsToFields) {
this.fieldsStore.updateFields(mapPropsToFields(nextProps));
}
},
deep: true,
},
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
mounted() {
this.cleanUpUselessFields();
2018-05-06 10:32:40 +00:00
},
2019-01-12 03:33:27 +00:00
updated() {
2019-01-14 14:42:04 +00:00
// form updated add for template v-decorator
2019-01-12 03:33:27 +00:00
this.cleanUpUselessFields();
},
2018-05-03 11:10:43 +00:00
methods: {
2019-01-12 03:33:27 +00:00
updateFields(fields = {}) {
this.fieldsStore.updateFields(mapPropsToFields(fields));
if (templateContext) {
2019-01-12 03:33:27 +00:00
templateContext.$forceUpdate();
}
},
2019-01-12 03:33:27 +00:00
onCollectCommon(name, action, args) {
const fieldMeta = this.fieldsStore.getFieldMeta(name);
2018-05-03 11:10:43 +00:00
if (fieldMeta[action]) {
2019-01-12 03:33:27 +00:00
fieldMeta[action](...args);
2018-05-03 11:10:43 +00:00
} else if (fieldMeta.originalProps && fieldMeta.originalProps[action]) {
2019-01-12 03:33:27 +00:00
fieldMeta.originalProps[action](...args);
2018-05-03 11:10:43 +00:00
}
const value = fieldMeta.getValueFromEvent
? fieldMeta.getValueFromEvent(...args)
2019-01-12 03:33:27 +00:00
: getValueFromEvent(...args);
2018-05-03 11:10:43 +00:00
if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) {
2019-01-12 03:33:27 +00:00
const valuesAll = this.fieldsStore.getAllValues();
const valuesAllSet = {};
valuesAll[name] = value;
Object.keys(valuesAll).forEach(key => set(valuesAllSet, key, valuesAll[key]));
onValuesChange(this, set({}, name, value), valuesAllSet);
}
const field = this.fieldsStore.getField(name);
return { name, field: { ...field, value, touched: true }, fieldMeta };
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
onCollect(name_, action, ...args) {
const { name, field, fieldMeta } = this.onCollectCommon(name_, action, args);
const { validate } = fieldMeta;
2018-05-03 11:10:43 +00:00
const newField = {
...field,
dirty: hasRules(validate),
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
this.setFields({
[name]: newField,
2019-01-12 03:33:27 +00:00
});
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
onCollectValidate(name_, action, ...args) {
const { field, fieldMeta } = this.onCollectCommon(name_, action, args);
2018-05-03 11:10:43 +00:00
const newField = {
...field,
dirty: true,
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
this.validateFieldsInternal([newField], {
action,
options: {
firstFields: !!fieldMeta.validateFirst,
},
2019-01-12 03:33:27 +00:00
});
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
getCacheBind(name, action, fn) {
2018-05-03 11:10:43 +00:00
if (!this.cachedBind[name]) {
2019-01-12 03:33:27 +00:00
this.cachedBind[name] = {};
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
const cache = this.cachedBind[name];
2018-10-31 13:39:12 +00:00
if (!cache[action] || cache[action].oriFn !== fn) {
cache[action] = {
fn: fn.bind(this, name, action),
oriFn: fn,
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
return cache[action].fn;
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
getFieldDecorator(name, fieldOption) {
const { props, ...restProps } = this.getFieldProps(name, fieldOption);
return fieldElem => {
2018-10-31 13:39:12 +00:00
// We should put field in record if it is rendered
2019-01-12 03:33:27 +00:00
this.renderFields[name] = true;
2018-10-31 13:39:12 +00:00
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(name);
const originalProps = getOptionProps(fieldElem);
const originalEvents = getEvents(fieldElem);
2018-05-03 11:10:43 +00:00
if (process.env.NODE_ENV !== 'production') {
2019-01-12 03:33:27 +00:00
const valuePropName = fieldMeta.valuePropName;
2018-05-03 11:10:43 +00:00
warning(
!(valuePropName in originalProps),
`\`getFieldDecorator\` will override \`${valuePropName}\`, ` +
2019-01-12 03:33:27 +00:00
`so please don't set \`${valuePropName} and v-model\` directly ` +
`and use \`setFieldsValue\` to set it.`,
);
const defaultValuePropName = `default${valuePropName[0].toUpperCase()}${valuePropName.slice(
1,
)}`;
2018-05-03 11:10:43 +00:00
warning(
!(defaultValuePropName in originalProps),
`\`${defaultValuePropName}\` is invalid ` +
2019-01-12 03:33:27 +00:00
`for \`getFieldDecorator\` will set \`${valuePropName}\`,` +
` please use \`option.initialValue\` instead.`,
);
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
fieldMeta.originalProps = originalProps;
2018-05-04 04:16:17 +00:00
// fieldMeta.ref = fieldElem.data && fieldElem.data.ref
const newProps = {
2018-05-03 11:10:43 +00:00
props: {
2018-05-03 14:53:17 +00:00
...props,
2018-05-03 11:10:43 +00:00
...this.fieldsStore.getFieldValuePropValue(fieldMeta),
},
2018-05-04 04:16:17 +00:00
...restProps,
2019-01-12 03:33:27 +00:00
};
newProps.domProps.value = newProps.props.value;
const newEvents = {};
Object.keys(newProps.on).forEach(key => {
2018-05-04 04:16:17 +00:00
if (originalEvents[key]) {
2019-01-12 03:33:27 +00:00
const triggerEvents = newProps.on[key];
2018-05-04 04:16:17 +00:00
newEvents[key] = (...args) => {
2019-01-12 03:33:27 +00:00
originalEvents[key](...args);
triggerEvents(...args);
};
2018-05-05 09:00:51 +00:00
} else {
2019-01-12 03:33:27 +00:00
newEvents[key] = newProps.on[key];
2018-05-04 04:16:17 +00:00
}
2019-01-12 03:33:27 +00:00
});
return cloneElement(fieldElem, { ...newProps, on: newEvents });
};
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
getFieldProps(name, usersFieldOption = {}) {
2018-05-03 11:10:43 +00:00
if (!name) {
2019-01-12 03:33:27 +00:00
throw new Error('Must call `getFieldProps` with valid name string!');
2018-05-03 11:10:43 +00:00
}
2018-05-02 13:35:42 +00:00
if (process.env.NODE_ENV !== 'production') {
warning(
2018-05-03 11:10:43 +00:00
this.fieldsStore.isValidNestedFieldName(name),
2019-01-12 03:33:27 +00:00
'One field name cannot be part of another, e.g. `a` and `a.b`.',
);
2018-05-02 13:35:42 +00:00
warning(
2018-05-03 11:10:43 +00:00
!('exclusive' in usersFieldOption),
2019-01-12 03:33:27 +00:00
'`option.exclusive` of `getFieldProps`|`getFieldDecorator` had been remove.',
);
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
delete this.clearedFieldMetaCache[name];
2018-05-02 13:35:42 +00:00
2018-05-03 11:10:43 +00:00
const fieldOption = {
name,
trigger: DEFAULT_TRIGGER,
valuePropName: 'value',
validate: [],
...usersFieldOption,
2019-01-12 03:33:27 +00:00
};
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
const { rules, trigger, validateTrigger = trigger, validate } = fieldOption;
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(name);
2018-05-03 11:10:43 +00:00
if ('initialValue' in fieldOption) {
2019-01-12 03:33:27 +00:00
fieldMeta.initialValue = fieldOption.initialValue;
2018-05-03 11:10:43 +00:00
}
2018-05-02 13:35:42 +00:00
2018-05-03 11:10:43 +00:00
const inputProps = {
...this.fieldsStore.getFieldValuePropValue(fieldOption),
2018-05-03 14:53:17 +00:00
// ref: name,
2019-01-12 03:33:27 +00:00
};
const inputListeners = {};
const inputAttrs = {};
2018-05-03 11:10:43 +00:00
if (fieldNameProp) {
2019-01-12 03:33:27 +00:00
inputProps[fieldNameProp] = formName ? `${formName}_${name}` : name;
2018-05-03 11:10:43 +00:00
}
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
const validateRules = normalizeValidateRules(validate, rules, validateTrigger);
const validateTriggers = getValidateTriggers(validateRules);
validateTriggers.forEach(action => {
if (inputListeners[action]) return;
inputListeners[action] = this.getCacheBind(name, action, this.onCollectValidate);
});
2018-05-02 13:35:42 +00:00
2018-05-03 11:10:43 +00:00
// make sure that the value will be collect
if (trigger && validateTriggers.indexOf(trigger) === -1) {
2019-01-12 03:33:27 +00:00
inputListeners[trigger] = this.getCacheBind(name, trigger, this.onCollect);
2018-05-03 11:10:43 +00:00
}
2018-05-02 13:35:42 +00:00
2018-05-03 11:10:43 +00:00
const meta = {
...fieldMeta,
...fieldOption,
validate: validateRules,
2019-01-12 03:33:27 +00:00
};
this.fieldsStore.setFieldMeta(name, meta);
2018-05-03 11:10:43 +00:00
if (fieldMetaProp) {
2019-01-12 03:33:27 +00:00
inputAttrs[fieldMetaProp] = meta;
2018-05-03 11:10:43 +00:00
}
2018-05-02 13:35:42 +00:00
2018-05-03 11:10:43 +00:00
if (fieldDataProp) {
2019-01-12 03:33:27 +00:00
inputAttrs[fieldDataProp] = this.fieldsStore.getField(name);
2018-05-03 11:10:43 +00:00
}
2018-10-31 13:39:12 +00:00
// This field is rendered, record it
2019-01-12 03:33:27 +00:00
this.renderFields[name] = true;
2018-05-03 14:53:17 +00:00
return {
2018-05-05 09:00:51 +00:00
props: omit(inputProps, ['id']),
// id: inputProps.id,
2018-05-04 04:16:17 +00:00
domProps: {
value: inputProps.value,
},
2018-05-05 09:00:51 +00:00
attrs: {
...inputAttrs,
id: inputProps.id,
},
2018-05-03 14:53:17 +00:00
directives: [
2018-05-04 04:16:17 +00:00
{
name: 'ant-ref',
value: this.getCacheBind(name, `${name}__ref`, this.saveRef),
},
2018-05-03 14:53:17 +00:00
],
2018-05-04 04:16:17 +00:00
on: inputListeners,
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
getFieldInstance(name) {
return this.instances[name];
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
getRules(fieldMeta, action) {
const actionRules = fieldMeta.validate
.filter(item => {
return !action || item.trigger.indexOf(action) >= 0;
})
.map(item => item.rules);
return flattenArray(actionRules);
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
setFields(maybeNestedFields, callback) {
const fields = this.fieldsStore.flattenRegisteredFields(maybeNestedFields);
this.fieldsStore.setFields(fields);
2018-05-03 11:10:43 +00:00
if (onFieldsChange) {
2019-01-12 03:33:27 +00:00
const changedFields = Object.keys(fields).reduce(
(acc, name) => set(acc, name, this.fieldsStore.getField(name)),
{},
);
onFieldsChange(this, changedFields, this.fieldsStore.getNestedAllFields());
2018-05-03 11:10:43 +00:00
}
2018-06-23 09:17:45 +00:00
if (templateContext) {
2019-01-12 03:33:27 +00:00
templateContext.$forceUpdate();
2018-06-23 09:17:45 +00:00
} else {
2019-01-12 03:33:27 +00:00
this.$forceUpdate();
2018-06-23 09:17:45 +00:00
}
2018-05-03 14:53:17 +00:00
this.$nextTick(() => {
2019-01-12 03:33:27 +00:00
callback && callback();
});
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
setFieldsValue(changedValues, callback) {
const { fieldsMeta } = this.fieldsStore;
const values = this.fieldsStore.flattenRegisteredFields(changedValues);
2018-05-03 11:10:43 +00:00
const newFields = Object.keys(values).reduce((acc, name) => {
2019-01-12 03:33:27 +00:00
const isRegistered = fieldsMeta[name];
2018-05-03 11:10:43 +00:00
if (process.env.NODE_ENV !== 'production') {
warning(
isRegistered,
'Cannot use `setFieldsValue` until ' +
2019-01-12 03:33:27 +00:00
'you use `getFieldDecorator` or `getFieldProps` to register it.',
);
2018-05-03 11:10:43 +00:00
}
if (isRegistered) {
2019-01-12 03:33:27 +00:00
const value = values[name];
2018-05-03 11:10:43 +00:00
acc[name] = {
value,
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
return acc;
}, {});
this.setFields(newFields, callback);
2018-05-03 11:10:43 +00:00
if (onValuesChange) {
2019-01-12 03:33:27 +00:00
const allValues = this.fieldsStore.getAllValues();
onValuesChange(this, changedValues, allValues);
2018-05-02 13:35:42 +00:00
}
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
saveRef(name, _, component) {
2018-05-03 14:53:17 +00:00
if (!component) {
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(name);
2019-01-01 08:25:50 +00:00
if (!fieldMeta.preserve) {
2019-01-12 03:33:27 +00:00
// after destroy, delete data
2019-01-01 08:25:50 +00:00
this.clearedFieldMetaCache[name] = {
field: this.fieldsStore.getField(name),
meta: fieldMeta,
2019-01-12 03:33:27 +00:00
};
this.clearField(name);
2018-05-03 14:53:17 +00:00
}
2019-01-12 03:33:27 +00:00
delete this.domFields[name];
return;
2018-05-03 14:53:17 +00:00
}
2019-01-12 03:33:27 +00:00
this.domFields[name] = true;
this.recoverClearedField(name);
2018-05-04 04:16:17 +00:00
// const fieldMeta = this.fieldsStore.getFieldMeta(name)
// if (fieldMeta) {
// const ref = fieldMeta.ref
// if (ref) {
// if (typeof ref === 'string') {
// throw new Error(`can not set ref string for ${name}`)
// }
// ref(component)
// }
// }
2019-01-12 03:33:27 +00:00
this.instances[name] = component;
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
cleanUpUselessFields() {
const fieldList = this.fieldsStore.getAllFieldsName();
2019-01-01 08:25:50 +00:00
const removedList = fieldList.filter(field => {
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(field);
return !this.renderFields[field] && !this.domFields[field] && !fieldMeta.preserve;
});
2018-10-31 13:39:12 +00:00
if (removedList.length) {
2019-01-12 03:33:27 +00:00
removedList.forEach(this.clearField);
2018-10-31 13:39:12 +00:00
}
2019-01-12 03:33:27 +00:00
this.renderFields = {};
2018-10-31 13:39:12 +00:00
},
2019-01-12 03:33:27 +00:00
clearField(name) {
this.fieldsStore.clearField(name);
delete this.instances[name];
delete this.cachedBind[name];
2018-10-31 13:39:12 +00:00
},
2019-01-12 03:33:27 +00:00
resetFields(ns) {
const newFields = this.fieldsStore.resetFields(ns);
2018-10-31 13:39:12 +00:00
if (Object.keys(newFields).length > 0) {
2019-01-12 03:33:27 +00:00
this.setFields(newFields);
2018-10-31 13:39:12 +00:00
}
if (ns) {
2019-01-12 03:33:27 +00:00
const names = Array.isArray(ns) ? ns : [ns];
names.forEach(name => delete this.clearedFieldMetaCache[name]);
2018-10-31 13:39:12 +00:00
} else {
2019-01-12 03:33:27 +00:00
this.clearedFieldMetaCache = {};
2018-10-31 13:39:12 +00:00
}
},
2019-01-12 03:33:27 +00:00
recoverClearedField(name) {
2018-10-31 13:39:12 +00:00
if (this.clearedFieldMetaCache[name]) {
this.fieldsStore.setFields({
[name]: this.clearedFieldMetaCache[name].field,
2019-01-12 03:33:27 +00:00
});
this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta);
delete this.clearedFieldMetaCache[name];
2018-10-31 13:39:12 +00:00
}
},
2019-01-12 03:33:27 +00:00
validateFieldsInternal(fields, { fieldNames, action, options = {} }, callback) {
const allRules = {};
const allValues = {};
const allFields = {};
const alreadyErrors = {};
fields.forEach(field => {
const name = field.name;
2018-05-03 11:10:43 +00:00
if (options.force !== true && field.dirty === false) {
if (field.errors) {
2019-01-12 03:33:27 +00:00
set(alreadyErrors, name, { errors: field.errors });
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
return;
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(name);
2018-05-03 11:10:43 +00:00
const newField = {
...field,
2019-01-12 03:33:27 +00:00
};
newField.errors = undefined;
newField.validating = true;
newField.dirty = true;
allRules[name] = this.getRules(fieldMeta, action);
allValues[name] = newField.value;
allFields[name] = newField;
});
this.setFields(allFields);
2018-05-03 11:10:43 +00:00
// in case normalize
2019-01-12 03:33:27 +00:00
Object.keys(allValues).forEach(f => {
allValues[f] = this.fieldsStore.getFieldValue(f);
});
2018-05-03 11:10:43 +00:00
if (callback && isEmptyObject(allFields)) {
2019-01-12 03:33:27 +00:00
callback(
isEmptyObject(alreadyErrors) ? null : alreadyErrors,
this.fieldsStore.getFieldsValue(fieldNames),
);
return;
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
const validator = new AsyncValidator(allRules);
2018-05-03 11:10:43 +00:00
if (validateMessages) {
2019-01-12 03:33:27 +00:00
validator.messages(validateMessages);
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
validator.validate(allValues, options, errors => {
2018-05-03 11:10:43 +00:00
const errorsGroup = {
...alreadyErrors,
2019-01-12 03:33:27 +00:00
};
2018-05-03 11:10:43 +00:00
if (errors && errors.length) {
2019-01-12 03:33:27 +00:00
errors.forEach(e => {
const fieldName = e.field;
const field = get(errorsGroup, fieldName);
2018-05-03 11:10:43 +00:00
if (typeof field !== 'object' || Array.isArray(field)) {
2019-01-12 03:33:27 +00:00
set(errorsGroup, fieldName, { errors: [] });
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
const fieldErrors = get(errorsGroup, fieldName.concat('.errors'));
fieldErrors.push(e);
});
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
const expired = [];
const nowAllFields = {};
Object.keys(allRules).forEach(name => {
const fieldErrors = get(errorsGroup, name);
const nowField = this.fieldsStore.getField(name);
2018-05-03 11:10:43 +00:00
// avoid concurrency problems
if (nowField.value !== allValues[name]) {
expired.push({
name,
2019-01-12 03:33:27 +00:00
});
2018-05-03 11:10:43 +00:00
} else {
2019-01-12 03:33:27 +00:00
nowField.errors = fieldErrors && fieldErrors.errors;
nowField.value = allValues[name];
nowField.validating = false;
nowField.dirty = false;
nowAllFields[name] = nowField;
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
});
this.setFields(nowAllFields);
2018-05-03 11:10:43 +00:00
if (callback) {
if (expired.length) {
expired.forEach(({ name }) => {
2019-01-12 03:33:27 +00:00
const fieldErrors = [
{
message: `${name} need to revalidate`,
field: name,
},
];
2018-05-03 11:10:43 +00:00
set(errorsGroup, name, {
expired: true,
errors: fieldErrors,
2019-01-12 03:33:27 +00:00
});
});
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
callback(
isEmptyObject(errorsGroup) ? null : errorsGroup,
this.fieldsStore.getFieldsValue(fieldNames),
);
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
});
2018-05-03 11:10:43 +00:00
},
2019-01-12 03:33:27 +00:00
validateFields(ns, opt, cb) {
2019-01-01 08:25:50 +00:00
const pending = new Promise((resolve, reject) => {
2019-01-12 03:33:27 +00:00
const { names, options } = getParams(ns, opt, cb);
let { callback } = getParams(ns, opt, cb);
2019-01-01 08:25:50 +00:00
if (!callback || typeof callback === 'function') {
2019-01-12 03:33:27 +00:00
const oldCb = callback;
2019-01-01 08:25:50 +00:00
callback = (errors, values) => {
if (oldCb) {
2019-01-12 03:33:27 +00:00
oldCb(errors, values);
2019-01-01 08:25:50 +00:00
} else if (errors) {
2019-01-12 03:33:27 +00:00
reject({ errors, values });
2019-01-01 08:25:50 +00:00
} else {
2019-01-12 03:33:27 +00:00
resolve(values);
2019-01-01 08:25:50 +00:00
}
2019-01-12 03:33:27 +00:00
};
2018-05-02 13:35:42 +00:00
}
2019-01-01 08:25:50 +00:00
const fieldNames = names
? this.fieldsStore.getValidFieldsFullName(names)
2019-01-12 03:33:27 +00:00
: this.fieldsStore.getValidFieldsName();
2019-01-01 08:25:50 +00:00
const fields = fieldNames
.filter(name => {
2019-01-12 03:33:27 +00:00
const fieldMeta = this.fieldsStore.getFieldMeta(name);
return hasRules(fieldMeta.validate);
2019-01-01 08:25:50 +00:00
})
2019-01-12 03:33:27 +00:00
.map(name => {
const field = this.fieldsStore.getField(name);
field.value = this.fieldsStore.getFieldValue(name);
return field;
});
2019-01-01 08:25:50 +00:00
if (!fields.length) {
if (callback) {
2019-01-12 03:33:27 +00:00
callback(null, this.fieldsStore.getFieldsValue(fieldNames));
2019-01-01 08:25:50 +00:00
}
2019-01-12 03:33:27 +00:00
return;
2019-01-01 08:25:50 +00:00
}
if (!('firstFields' in options)) {
2019-01-12 03:33:27 +00:00
options.firstFields = fieldNames.filter(name => {
const fieldMeta = this.fieldsStore.getFieldMeta(name);
return !!fieldMeta.validateFirst;
});
2019-01-01 08:25:50 +00:00
}
2019-01-12 03:33:27 +00:00
this.validateFieldsInternal(
fields,
{
fieldNames,
options,
},
callback,
);
});
2019-01-21 14:14:30 +00:00
pending.catch(e => {
if (console.error) {
console.error(e);
2019-01-21 13:59:13 +00:00
}
return e;
});
2019-01-12 03:33:27 +00:00
return pending;
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
isSubmitting() {
2018-05-03 11:10:43 +00:00
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
warning(
false,
'`isSubmitting` is deprecated. ' +
2019-01-12 03:33:27 +00:00
"Actually, it's more convenient to handle submitting status by yourself.",
);
2018-05-03 11:10:43 +00:00
}
2019-01-12 03:33:27 +00:00
return this.submitting;
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
2019-01-12 03:33:27 +00:00
submit(callback) {
2018-05-03 11:10:43 +00:00
if (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') {
warning(
false,
'`submit` is deprecated.' +
2019-01-12 03:33:27 +00:00
"Actually, it's more convenient to handle submitting status by yourself.",
);
2018-05-03 11:10:43 +00:00
}
const fn = () => {
this.setState({
submitting: false,
2019-01-12 03:33:27 +00:00
});
};
2018-05-02 13:35:42 +00:00
this.setState({
2018-05-03 11:10:43 +00:00
submitting: true,
2019-01-12 03:33:27 +00:00
});
callback(fn);
2018-05-03 11:10:43 +00:00
},
2018-05-02 13:35:42 +00:00
},
2019-01-12 03:33:27 +00:00
render() {
const { $listeners, $slots } = this;
2018-05-02 13:35:42 +00:00
const formProps = {
[formPropName]: this.getForm(),
2019-01-12 03:33:27 +00:00
};
2019-01-15 01:41:07 +00:00
const { wrappedComponentRef, ...restProps } = getOptionProps(this);
2018-05-03 11:10:43 +00:00
const wrappedComponentProps = {
props: mapProps.call(this, {
...formProps,
2019-01-14 14:42:04 +00:00
...restProps,
2018-05-03 11:10:43 +00:00
}),
on: $listeners,
2018-05-06 10:32:40 +00:00
ref: 'WrappedComponent',
2019-01-14 14:42:04 +00:00
directives: [
{
name: 'ant-ref',
value: wrappedComponentRef,
},
],
2019-01-12 03:33:27 +00:00
};
2019-01-12 03:33:27 +00:00
return WrappedComponent ? (
<WrappedComponent {...wrappedComponentProps}>{$slots.default}</WrappedComponent>
) : null;
2018-05-02 13:35:42 +00:00
},
2019-01-12 03:33:27 +00:00
};
if (!WrappedComponent) return Form;
2018-05-06 10:32:40 +00:00
if (Array.isArray(WrappedComponent.props)) {
2019-01-12 03:33:27 +00:00
const newProps = {};
WrappedComponent.props.forEach(prop => {
newProps[prop] = PropTypes.any;
});
newProps[formPropName] = Object;
WrappedComponent.props = newProps;
2018-05-06 10:32:40 +00:00
} else {
2019-01-12 03:33:27 +00:00
WrappedComponent.props = WrappedComponent.props || {};
2018-05-06 10:32:40 +00:00
if (!(formPropName in WrappedComponent.props)) {
2019-01-12 03:33:27 +00:00
WrappedComponent.props[formPropName] = Object;
2018-05-04 08:02:31 +00:00
}
}
2019-01-12 03:33:27 +00:00
return argumentContainer(Form, WrappedComponent);
};
2018-05-02 13:35:42 +00:00
}
2019-01-12 03:33:27 +00:00
export default createBaseForm;