diff --git a/components/_util/FormDecoratorDirective.js b/components/_util/FormDecoratorDirective.js new file mode 100644 index 000000000..1fc7ecf23 --- /dev/null +++ b/components/_util/FormDecoratorDirective.js @@ -0,0 +1,7 @@ +export default { + // just for tag + install: (Vue, options) => { + Vue.directive('decorator', { + }) + }, +} diff --git a/components/_util/props-util.js b/components/_util/props-util.js index 9fddb4427..34a316f14 100644 --- a/components/_util/props-util.js +++ b/components/_util/props-util.js @@ -49,7 +49,7 @@ const getSlots = (ele) => { if (ele.$vnode) { componentOptions = ele.$vnode.componentOptions || {} } - const children = componentOptions.children || [] + const children = ele.children || componentOptions.children || [] const slots = {} children.forEach(child => { const name = (child.data && child.data.slot) || 'default' diff --git a/components/form/Form.jsx b/components/form/Form.jsx index e2e44833e..bf27ecc96 100755 --- a/components/form/Form.jsx +++ b/components/form/Form.jsx @@ -1,6 +1,8 @@ import PropTypes from '../_util/vue-types' import classNames from 'classnames' +import Vue from 'vue' import isRegExp from 'lodash/isRegExp' +import warning from '../_util/warning' import createDOMForm from '../vc-form/src/createDOMForm' import createFormField from '../vc-form/src/createFormField' import FormItem from './FormItem' @@ -54,7 +56,7 @@ export const WrappedFormUtils = { export const FormProps = { layout: PropTypes.oneOf(['horizontal', 'inline', 'vertical']), - form: PropTypes.shape(WrappedFormUtils).loose, + form: PropTypes.object, // onSubmit: React.FormEventHandler; prefixCls: PropTypes.string, hideRequiredMark: PropTypes.bool, @@ -110,29 +112,13 @@ export const ValidationRule = { // validateFirst?: boolean; // }; -export default { +const Form = { name: 'AForm', props: initDefaultProps(FormProps, { prefixCls: 'ant-form', layout: 'horizontal', hideRequiredMark: false, }), - // static defaultProps = { - // prefixCls: 'ant-form', - // layout: 'horizontal', - // hideRequiredMark: false, - // onSubmit (e) { - // e.preventDefault() - // }, - // }; - - // static propTypes = { - // prefixCls: PropTypes.string, - // layout: PropTypes.oneOf(['horizontal', 'inline', 'vertical']), - // children: PropTypes.any, - // onSubmit: PropTypes.func, - // hideRequiredMark: PropTypes.bool, - // }; Item: FormItem, @@ -146,11 +132,19 @@ export default { fieldDataProp: FIELD_DATA_PROP, }) }, + createForm (context, options = {}) { + return new Vue(Form.create({ ...options, templateContext: context })()) + }, provide () { return { FormProps: this.$props, } }, + watch: { + form () { + this.$forceUpdate() + }, + }, methods: { onSubmit (e) { const { $listeners } = this @@ -174,6 +168,10 @@ export default { [`${prefixCls}-hide-required-mark`]: hideRequiredMark, }) if (autoFormCreate) { + warning( + false, + '`autoFormCreate` is deprecated. please use `form` instead.' + ) const DomForm = this.DomForm || createDOMForm({ fieldNameProp: 'id', ...options, @@ -214,3 +212,5 @@ export default { return
{$slots.default}
}, } + +export default Form diff --git a/components/form/FormItem.jsx b/components/form/FormItem.jsx index adc20f6c2..8539394ec 100644 --- a/components/form/FormItem.jsx +++ b/components/form/FormItem.jsx @@ -1,14 +1,15 @@ import intersperse from 'intersperse' import PropTypes from '../_util/vue-types' import classNames from 'classnames' +import find from 'lodash/find' import Row from '../grid/Row' import Col, { ColProps } from '../grid/Col' import warning from '../_util/warning' import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants' -import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, getSlots, isValidElement } from '../_util/props-util' +import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, isValidElement, getSlots } from '../_util/props-util' import getTransitionProps from '../_util/getTransitionProps' import BaseMixin from '../_util/BaseMixin' -import { cloneElement } from '../_util/vnode' +import { cloneElement, cloneVNodes } from '../_util/vnode' export const FormItemProps = { id: PropTypes.string, prefixCls: PropTypes.string, @@ -47,6 +48,10 @@ export default { '`Form.Item` cannot generate `validateStatus` and `help` automatically, ' + 'while there are more than one `getFieldDecorator` in it.', ) + warning( + !this.fieldDecoratorId, + '`fieldDecoratorId` is deprecated. please use `v-decorator={id, options}` instead.' + ) }, methods: { getHelpMessage () { @@ -81,11 +86,8 @@ export default { if (getSlotOptions(child).__ANT_FORM_ITEM) { continue } - const attrs = child.data && child.data.attrs - if (!attrs) { - continue - } const slots = getSlots(child) + const attrs = child.data && child.data.attrs || {} if (FIELD_META_PROP in attrs) { // And means FIELD_DATA_PROP in child.props, too. controls.push(child) } else if (slots.default) { @@ -339,11 +341,34 @@ export default { ) }, + decoratorOption (vnode) { + if (vnode.data && vnode.data.directives) { + const directive = find(vnode.data.directives, ['name', 'decorator']) || {} + return directive.value || null + } else { + return null + } + }, + decoratorChildren (vnodes) { + const { FormProps } = this + const getFieldDecorator = FormProps.form.getFieldDecorator + vnodes.forEach((vnode, index) => { + const option = this.decoratorOption(vnode) + if (option && option.id) { + vnodes[index] = getFieldDecorator(option.id, option.options || {})(vnode) + } else if (vnode.children) { + vnode.children = this.decoratorChildren(cloneVNodes(vnode.children)) + } else if (vnode.componentOptions && vnode.componentOptions.children) { + vnode.componentOptions.children = this.decoratorChildren(cloneVNodes(vnode.componentOptions.children)) + } + }) + return vnodes + }, }, render () { - const { $slots, decoratorFormProps, fieldDecoratorId, fieldDecoratorOptions = {}} = this - const child = filterEmpty($slots.default || []) + const { $slots, decoratorFormProps, fieldDecoratorId, fieldDecoratorOptions = {}, FormProps } = this + let child = filterEmpty($slots.default || []) if (decoratorFormProps.form && fieldDecoratorId && child.length) { const getFieldDecorator = decoratorFormProps.form.getFieldDecorator child[0] = getFieldDecorator(fieldDecoratorId, fieldDecoratorOptions)(child[0]) @@ -351,9 +376,14 @@ export default { !(child.length > 1), '`autoFormCreate` just `decorator` then first children. but you can use JSX to support multiple children', ) + this.slotDefault = child + } else if (FormProps.form) { + child = cloneVNodes(child) + this.slotDefault = this.decoratorChildren(child) + } else { + this.slotDefault = child } - this.slotDefault = child const children = this.renderChildren() return this.renderFormItem(children) }, diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index 59caed30a..cd2b0cd7d 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -580,7 +580,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
-
+
diff --git a/components/form/demo/coordinated.vue b/components/form/demo/coordinated.vue index 359155f7c..5c68035b4 100644 --- a/components/form/demo/coordinated.vue +++ b/components/form/demo/coordinated.vue @@ -10,24 +10,29 @@ Use `setFieldsValue` to set other control's value programmaticly.