diff --git a/components/vc-form/index.js b/components/vc-form/index.js index e1b327a38..160f2c58b 100644 --- a/components/vc-form/index.js +++ b/components/vc-form/index.js @@ -1,3 +1,3 @@ -// based on rc-form 2.2.1 +// based on rc-form 2.2.6 import { createForm, createFormField } from './src/' export { createForm, createFormField } diff --git a/components/vc-form/src/createBaseForm.jsx b/components/vc-form/src/createBaseForm.jsx index 79dcf5c05..55905b9a4 100644 --- a/components/vc-form/src/createBaseForm.jsx +++ b/components/vc-form/src/createBaseForm.jsx @@ -59,7 +59,11 @@ function createBaseForm (option = {}, mixins = []) { this.instances = {} this.cachedBind = {} - this.clearedFieldMetaCache = {}; + this.clearedFieldMetaCache = {} + + this.renderFields = {} + this.domFields = {}; + // HACK: https://github.com/ant-design/ant-design/issues/6406 ['getFieldsValue', 'getFieldValue', @@ -91,9 +95,11 @@ function createBaseForm (option = {}, mixins = []) { }, mounted () { this.wrappedComponentRef(this.$refs.WrappedComponent) + this.cleanUpUselessFields() }, updated () { this.wrappedComponentRef(this.$refs.WrappedComponent) + this.cleanUpUselessFields() }, destroyed () { this.wrappedComponentRef(null) @@ -151,25 +157,21 @@ function createBaseForm (option = {}, mixins = []) { this.cachedBind[name] = {} } const cache = this.cachedBind[name] - if (!cache[action]) { - cache[action] = fn.bind(this, name, action) - } - return cache[action] - }, - - recoverClearedField (name) { - if (this.clearedFieldMetaCache[name]) { - this.fieldsStore.setFields({ - [name]: this.clearedFieldMetaCache[name].field, - }) - this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta) - delete this.clearedFieldMetaCache[name] + if (!cache[action] || cache[action].oriFn !== fn) { + cache[action] = { + fn: fn.bind(this, name, action), + oriFn: fn, + } } + return cache[action].fn }, getFieldDecorator (name, fieldOption) { const { props, ...restProps } = this.getFieldProps(name, fieldOption) return (fieldElem) => { + // We should put field in record if it is rendered + this.renderFields[name] = true + const fieldMeta = this.fieldsStore.getFieldMeta(name) const originalProps = getOptionProps(fieldElem) const originalEvents = getEvents(fieldElem) @@ -288,7 +290,8 @@ function createBaseForm (option = {}, mixins = []) { if (fieldDataProp) { inputAttrs[fieldDataProp] = this.fieldsStore.getField(name) } - + // This field is rendered, record it + this.renderFields[name] = true return { props: omit(inputProps, ['id']), // id: inputProps.id, @@ -338,19 +341,6 @@ function createBaseForm (option = {}, mixins = []) { }) }, - resetFields (ns) { - const newFields = this.fieldsStore.resetFields(ns) - if (Object.keys(newFields).length > 0) { - this.setFields(newFields) - } - if (ns) { - const names = Array.isArray(ns) ? ns : [ns] - names.forEach(name => delete this.clearedFieldMetaCache[name]) - } else { - this.clearedFieldMetaCache = {} - } - }, - setFieldsValue (changedValues, callback) { const { fieldsMeta } = this.fieldsStore const values = this.fieldsStore.flattenRegisteredFields(changedValues) @@ -385,11 +375,11 @@ function createBaseForm (option = {}, mixins = []) { field: this.fieldsStore.getField(name), meta: this.fieldsStore.getFieldMeta(name), } - this.fieldsStore.clearField(name) - delete this.instances[name] - delete this.cachedBind[name] + this.clearField(name) + delete this.domFields[name] return } + this.domFields[name] = true this.recoverClearedField(name) // const fieldMeta = this.fieldsStore.getFieldMeta(name) // if (fieldMeta) { @@ -404,6 +394,46 @@ function createBaseForm (option = {}, mixins = []) { this.instances[name] = component }, + cleanUpUselessFields () { + const fieldList = this.fieldsStore.getAllFieldsName() + const removedList = fieldList.filter(field => ( + !this.renderFields[field] && !this.domFields[field] + )) + if (removedList.length) { + removedList.forEach(this.clearField) + } + this.renderFields = {} + }, + + clearField (name) { + this.fieldsStore.clearField(name) + delete this.instances[name] + delete this.cachedBind[name] + }, + + resetFields (ns) { + const newFields = this.fieldsStore.resetFields(ns) + if (Object.keys(newFields).length > 0) { + this.setFields(newFields) + } + if (ns) { + const names = Array.isArray(ns) ? ns : [ns] + names.forEach(name => delete this.clearedFieldMetaCache[name]) + } else { + this.clearedFieldMetaCache = {} + } + }, + + recoverClearedField (name) { + if (this.clearedFieldMetaCache[name]) { + this.fieldsStore.setFields({ + [name]: this.clearedFieldMetaCache[name].field, + }) + this.fieldsStore.setFieldMeta(name, this.clearedFieldMetaCache[name].meta) + delete this.clearedFieldMetaCache[name] + } + }, + validateFieldsInternal (fields, { fieldNames, action, diff --git a/components/vc-form/src/createDOMForm.jsx b/components/vc-form/src/createDOMForm.jsx index 806da2e92..fdd756348 100644 --- a/components/vc-form/src/createDOMForm.jsx +++ b/components/vc-form/src/createDOMForm.jsx @@ -65,7 +65,7 @@ const mixin = { const validNames = this.fieldsStore.getValidFieldsName() let firstNode let firstTop - for (const name of validNames) { + validNames.forEach((name) => { if (has(error, name)) { const instance = this.getFieldInstance(name) if (instance) { @@ -77,7 +77,8 @@ const mixin = { } } } - } + }) + if (firstNode) { const c = options.container || getScrollableContainer(firstNode) scrollIntoView(firstNode, c, { diff --git a/components/vc-form/src/createFieldsStore.jsx b/components/vc-form/src/createFieldsStore.jsx index 0744bfc8d..b3511a383 100644 --- a/components/vc-form/src/createFieldsStore.jsx +++ b/components/vc-form/src/createFieldsStore.jsx @@ -10,22 +10,22 @@ function partOf (a, b) { return b.indexOf(a) === 0 && ['.', '['].indexOf(b[a.length]) !== -1 } +function internalFlattenFields (fields) { + return flattenFields( + fields, + (_, node) => isFormField(node), + 'You must wrap field data with `createFormField`.' + ) +} + class FieldsStore { constructor (fields) { - this.fields = this.flattenFields(fields) + this.fields = internalFlattenFields(fields) this.fieldsMeta = {} } updateFields (fields) { - this.fields = this.flattenFields(fields) - } - - flattenFields (fields) { - return flattenFields( - fields, - (_, node) => isFormField(node), - 'You must wrap field data with `createFormField`.' - ) + this.fields = internalFlattenFields(fields) } flattenRegisteredFields (fields) { @@ -33,7 +33,7 @@ class FieldsStore { return flattenFields( fields, path => validFieldsName.indexOf(path) >= 0, - 'You cannot set field before registering it.' + 'You cannot set a form field before rendering a field associated with the value.' ) } @@ -58,7 +58,9 @@ class FieldsStore { } const nowValues = {} Object.keys(fieldsMeta) - .forEach((f) => { nowValues[f] = this.getValueFromFields(f, nowFields) }) + .forEach((f) => { + nowValues[f] = this.getValueFromFields(f, nowFields) + }) Object.keys(nowValues).forEach((f) => { const value = nowValues[f] const fieldMeta = this.getFieldMeta(f) diff --git a/components/vc-form/src/index.jsx b/components/vc-form/src/index.jsx index 344a848c6..2c4be530d 100644 --- a/components/vc-form/src/index.jsx +++ b/components/vc-form/src/index.jsx @@ -6,4 +6,4 @@ import Vue from 'vue' import antRefDirective from '../../_util/antRefDirective' Vue.use(antRefDirective) -export { createForm, createFormField, formShape } +export { createFormField, formShape, createForm } diff --git a/components/vc-form/src/utils.js b/components/vc-form/src/utils.js index 89cd5050a..ec0baa50a 100644 --- a/components/vc-form/src/utils.js +++ b/components/vc-form/src/utils.js @@ -1,3 +1,5 @@ +import warning from 'warning' + function getDisplayName (WrappedComponent) { return WrappedComponent.name || 'WrappedComponent' } @@ -22,7 +24,7 @@ export function treeTraverse (path = '', tree, isLeafNode, errorMessage, callbac if (isLeafNode(path, tree)) { callback(path, tree) } else if (tree === undefined || tree === null) { - return + // Do nothing } else if (Array.isArray(tree)) { tree.forEach((subTree, index) => treeTraverse( `${path}[${index}]`, @@ -33,7 +35,7 @@ export function treeTraverse (path = '', tree, isLeafNode, errorMessage, callbac )) } else { // It's object and not a leaf node if (typeof tree !== 'object') { - console.error(errorMessage) + warning(false, errorMessage) return } Object.keys(tree).forEach(subTreeKey => {