mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-03 04:27:41 +08:00
feat: support form template
This commit is contained in:
parent
090f9cba5d
commit
868ee1ebaf
@ -57,7 +57,8 @@ export const FormProps = {
|
||||
// onSubmit: React.FormEventHandler<any>;
|
||||
prefixCls: PropTypes.string,
|
||||
hideRequiredMark: PropTypes.bool,
|
||||
formRef: PropTypes.func,
|
||||
autoFormCreate: PropTypes.func,
|
||||
options: PropTypes.object,
|
||||
}
|
||||
|
||||
export const ValidationRule = {
|
||||
@ -144,23 +145,6 @@ export default {
|
||||
fieldDataProp: FIELD_DATA_PROP,
|
||||
})
|
||||
},
|
||||
|
||||
// constructor (props) {
|
||||
// super(props)
|
||||
|
||||
// warning(!props.form, 'It is unnecessary to pass `form` to `Form` after antd@1.7.0.')
|
||||
// }
|
||||
|
||||
// shouldComponentUpdate(...args) {
|
||||
// return PureRenderMixin.shouldComponentUpdate.apply(this, args);
|
||||
// }
|
||||
|
||||
// getChildContext () {
|
||||
// const { layout } = this.props
|
||||
// return {
|
||||
// vertical: layout === 'vertical',
|
||||
// }
|
||||
// },
|
||||
provide () {
|
||||
return {
|
||||
FormProps: this.$props,
|
||||
@ -179,7 +163,7 @@ export default {
|
||||
|
||||
render () {
|
||||
const {
|
||||
prefixCls, hideRequiredMark, layout, onSubmit, $slots, formRef,
|
||||
prefixCls, hideRequiredMark, layout, onSubmit, $slots, autoFormCreate, options = {},
|
||||
} = this
|
||||
|
||||
const formClassName = classNames(prefixCls, {
|
||||
@ -188,25 +172,45 @@ export default {
|
||||
[`${prefixCls}-inline`]: layout === 'inline',
|
||||
[`${prefixCls}-hide-required-mark`]: hideRequiredMark,
|
||||
})
|
||||
if (formRef) {
|
||||
const NewForm = createDOMForm({
|
||||
if (autoFormCreate) {
|
||||
const saveFormRef = (ref) => {
|
||||
this.domForm = ref
|
||||
}
|
||||
const DomForm = this.DomForm || createDOMForm({
|
||||
fieldNameProp: 'id',
|
||||
...options,
|
||||
fieldMetaProp: FIELD_META_PROP,
|
||||
fieldDataProp: FIELD_DATA_PROP,
|
||||
templateContext: this.$parent,
|
||||
})({
|
||||
provide () {
|
||||
return {
|
||||
NewFormProps: this.$props,
|
||||
decoratorFormProps: this.$props,
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
children: $slots.default,
|
||||
formClassName: formClassName,
|
||||
submit: onSubmit,
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
formRef(this.form)
|
||||
autoFormCreate(this.form)
|
||||
},
|
||||
render () {
|
||||
return <form onSubmit={onSubmit} class={formClassName}>{$slots.default}</form>
|
||||
const { children, formClassName, submit } = this
|
||||
return <form onSubmit={submit} class={formClassName}>{children}</form>
|
||||
},
|
||||
})
|
||||
return <NewForm />
|
||||
if (this.domForm) {
|
||||
this.domForm.children = $slots.default
|
||||
this.domForm.submit = onSubmit
|
||||
this.domForm.formClassName = formClassName
|
||||
}
|
||||
this.DomForm = DomForm
|
||||
|
||||
return <DomForm wrappedComponentRef={(inst) => saveFormRef(inst)}/>
|
||||
}
|
||||
|
||||
return <form onSubmit={onSubmit} class={formClassName}>{$slots.default}</form>
|
||||
|
@ -5,7 +5,7 @@ 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 } from '../_util/props-util'
|
||||
import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, getSlots, isEmptyElement } from '../_util/props-util'
|
||||
import getTransitionProps from '../_util/getTransitionProps'
|
||||
import BaseMixin from '../_util/BaseMixin'
|
||||
export const FormItemProps = {
|
||||
@ -35,14 +35,14 @@ export default {
|
||||
}),
|
||||
inject: {
|
||||
FormProps: { default: {}},
|
||||
NewFormProps: { default: {}},
|
||||
decoratorFormProps: { default: {}},
|
||||
},
|
||||
data () {
|
||||
return { helpShow: false }
|
||||
},
|
||||
mounted () {
|
||||
warning(
|
||||
this.getControls(this.$slots.default, true).length <= 1,
|
||||
this.getControls(this.slotDefault, true).length <= 1,
|
||||
'`Form.Item` cannot generate `validateStatus` and `help` automatically, ' +
|
||||
'while there are more than one `getFieldDecorator` in it.',
|
||||
)
|
||||
@ -306,10 +306,10 @@ export default {
|
||||
) : null
|
||||
},
|
||||
renderChildren () {
|
||||
// const { $slots, FormProps, NewFormProps, prop } = this
|
||||
// const { $slots, FormProps, decoratorFormProps, prop } = this
|
||||
// const child = filterEmpty($slots.default || [])
|
||||
// if (NewFormProps.form && prop && child.length) {
|
||||
// const getFieldDecorator = NewFormProps.form.getFieldDecorator
|
||||
// if (decoratorFormProps.form && prop && child.length) {
|
||||
// const getFieldDecorator = decoratorFormProps.form.getFieldDecorator
|
||||
// const rules = FormProps.rules[prop] || []
|
||||
// child[0] = getFieldDecorator(prop, {
|
||||
// rules,
|
||||
@ -344,10 +344,10 @@ export default {
|
||||
},
|
||||
|
||||
render () {
|
||||
const { $slots, NewFormProps, fieldDecoratorId, fieldDecoratorOptions = {}} = this
|
||||
const { $slots, decoratorFormProps, fieldDecoratorId, fieldDecoratorOptions = {}} = this
|
||||
const child = filterEmpty($slots.default || [])
|
||||
if (NewFormProps.form && fieldDecoratorId && child.length) {
|
||||
const getFieldDecorator = NewFormProps.form.getFieldDecorator
|
||||
if (decoratorFormProps.form && fieldDecoratorId && child.length) {
|
||||
const getFieldDecorator = decoratorFormProps.form.getFieldDecorator
|
||||
child[0] = getFieldDecorator(fieldDecoratorId, fieldDecoratorOptions)(child[0])
|
||||
}
|
||||
this.slotDefault = child
|
||||
|
@ -9,10 +9,49 @@ Use `setFieldsValue` to set other control's value programmaticly.
|
||||
</us>
|
||||
|
||||
|
||||
<script>
|
||||
import { Form } from 'vue-antd-ui'
|
||||
<template>
|
||||
<a-form @submit="handleSubmit" :autoFormCreate="(form)=>{this.form = form}">
|
||||
<a-form-item
|
||||
label='Note'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="note"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your note!' }]}"
|
||||
>
|
||||
<a-input />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label='Gender'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="gender"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please select your gender!' }]}"
|
||||
>
|
||||
<a-select
|
||||
placeholder='Select a option and change input text above'
|
||||
@change="this.handleSelectChange"
|
||||
>
|
||||
<a-select-option value='male'>male</a-select-option>
|
||||
<a-select-option value='female'>female</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:wrapperCol="{ span: 12, offset: 5 }"
|
||||
>
|
||||
<a-button type='primary' htmlType='submit'>
|
||||
Submit
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
const CoordinatedForm = {
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formLayout: 'horizontal',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
@ -29,54 +68,10 @@ const CoordinatedForm = {
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { getFieldDecorator } = this.form
|
||||
return (
|
||||
<a-form onSubmit={this.handleSubmit}>
|
||||
<a-form-item
|
||||
label='Note'
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 12 }}
|
||||
>
|
||||
{getFieldDecorator('note', {
|
||||
rules: [{ required: true, message: 'Please input your note!' }],
|
||||
})(
|
||||
<a-input />
|
||||
)}
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label='Gender'
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 12 }}
|
||||
>
|
||||
{getFieldDecorator('gender', {
|
||||
rules: [{ required: true, message: 'Please select your gender!' }],
|
||||
})(
|
||||
<a-select
|
||||
placeholder='Select a option and change input text above'
|
||||
onChange={this.handleSelectChange}
|
||||
>
|
||||
<a-select-option value='male'>male</a-select-option>
|
||||
<a-select-option value='female'>female</a-select-option>
|
||||
</a-select>
|
||||
)}
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
wrapperCol={{ span: 12, offset: 5 }}
|
||||
>
|
||||
<a-button type='primary' htmlType='submit'>
|
||||
Submit
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default Form.create()(CoordinatedForm)
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9,9 +9,39 @@ Perform different check rules according to different situations.
|
||||
</us>
|
||||
|
||||
|
||||
<script>
|
||||
import { Form } from 'vue-antd-ui'
|
||||
<template>
|
||||
<a-form :autoFormCreate="(form)=>{this.form = form}">
|
||||
<a-form-item
|
||||
:formItemLayout="formItemLayout"
|
||||
label='Name'
|
||||
fieldDecoratorId="username"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your name' }]}"
|
||||
>
|
||||
<a-input placeholder='Please input your name' />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:formItemLayout="formItemLayout"
|
||||
label='Nickname'
|
||||
fieldDecoratorId="nickname"
|
||||
:fieldDecoratorOptions="{rules: [{ required: checkNick, message: 'Please input your nickname' }]}"
|
||||
>
|
||||
<a-input placeholder='Please input your nickname' />
|
||||
</a-form-item>
|
||||
<a-form-item :formTailLayout="formTailLayout">
|
||||
<a-checkbox
|
||||
:checked="checkNick"
|
||||
@change="handleChange"
|
||||
>
|
||||
Nickname is required
|
||||
</a-checkbox>
|
||||
</a-form-item>
|
||||
<a-form-item :formTailLayout="formTailLayout">
|
||||
<a-button type='primary' @click="check">Check</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 8 },
|
||||
@ -20,10 +50,12 @@ const formTailLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 8, offset: 4 },
|
||||
}
|
||||
const DynamicRule = {
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
checkNick: false,
|
||||
formItemLayout,
|
||||
formTailLayout,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -43,52 +75,10 @@ const DynamicRule = {
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { getFieldDecorator } = this.form
|
||||
return (
|
||||
<div>
|
||||
<a-form-item {...{ props: formItemLayout }} label='Name'>
|
||||
{getFieldDecorator('username', {
|
||||
rules: [{
|
||||
required: true,
|
||||
message: 'Please input your name',
|
||||
}],
|
||||
})(
|
||||
<a-input placeholder='Please input your name' />
|
||||
)}
|
||||
</a-form-item>
|
||||
<a-form-item {...{ props: formItemLayout }} label='Nickname'>
|
||||
{getFieldDecorator('nickname', {
|
||||
rules: [{
|
||||
required: this.checkNick,
|
||||
message: 'Please input your nickname',
|
||||
}],
|
||||
})(
|
||||
<a-input placeholder='Please input your nickname' />
|
||||
)}
|
||||
</a-form-item>
|
||||
<a-form-item {...{ props: formTailLayout }}>
|
||||
<a-checkbox
|
||||
value={this.checkNick}
|
||||
onChange={this.handleChange}
|
||||
>
|
||||
Nickname is required
|
||||
</a-checkbox>
|
||||
</a-form-item>
|
||||
<a-form-item {...{ props: formTailLayout }}>
|
||||
<a-button type='primary' onClick={this.check}>
|
||||
Check
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
export default Form.create()(DynamicRule)
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,57 +1,73 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-form @submit="handleSubmit" :formRef="(form)=>{this.form = form}">
|
||||
<a-form layout='inline' @submit="handleSubmit" :autoFormCreate="(form)=>{this.form = form}">
|
||||
<template v-if="form">
|
||||
<a-form-item
|
||||
label='Note'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="note"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your note!' }]}"
|
||||
:validateStatus="userNameError() ? 'error' : ''"
|
||||
:help="userNameError() || ''"
|
||||
fieldDecoratorId="userName"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your username!' }]}"
|
||||
>
|
||||
<a-input />
|
||||
<a-input placeholder='Username'>
|
||||
<a-icon slot="prefix" type='user' style="color:rgba(0,0,0,.25)"/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label='Gender'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="gender"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please select your gender!' }]}"
|
||||
:validateStatus="passwordError() ? 'error' : ''"
|
||||
:help="passwordError() || ''"
|
||||
fieldDecoratorId="password"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your Password!' }]}"
|
||||
>
|
||||
<a-select
|
||||
placeholder='Select a option and change input text above'
|
||||
@change="this.handleSelectChange"
|
||||
<a-input type='password' placeholder='Password'>
|
||||
<a-icon slot="prefix" type='lock' style="color:rgba(0,0,0,.25)"/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type='primary'
|
||||
htmlType='submit'
|
||||
:disabled="hasErrors(form.getFieldsError())"
|
||||
>
|
||||
<a-select-option value='male'>male</a-select-option>
|
||||
<a-select-option value='female'>female</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:wrapperCol="{ span: 12, offset: 5 }"
|
||||
>
|
||||
<a-button type='primary' htmlType='submit'>
|
||||
Submit
|
||||
Log in
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
function hasErrors (fieldsError) {
|
||||
return Object.keys(fieldsError).some(field => fieldsError[field])
|
||||
}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
formLayout: 'horizontal',
|
||||
rules: {
|
||||
test: [{
|
||||
type: 'email', message: 'The input is not valid E-mail!',
|
||||
}, {
|
||||
required: true, message: 'Please input your E-mail!',
|
||||
}],
|
||||
},
|
||||
hasErrors,
|
||||
form: null,
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
},
|
||||
watch: {
|
||||
form (val) {
|
||||
this.$nextTick(() => {
|
||||
// To disabled submit button at the beginning.
|
||||
this.form.validateFields()
|
||||
})
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleSubmit (e) {
|
||||
// Only show error after a field is touched.
|
||||
userNameError () {
|
||||
const { getFieldError, isFieldTouched } = this.form
|
||||
return isFieldTouched('userName') && getFieldError('userName')
|
||||
},
|
||||
// Only show error after a field is touched.
|
||||
passwordError () {
|
||||
const { getFieldError, isFieldTouched } = this.form
|
||||
return isFieldTouched('password') && getFieldError('password')
|
||||
},
|
||||
handleSubmit (e) {
|
||||
e.preventDefault()
|
||||
this.form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
@ -59,12 +75,6 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelectChange (value) {
|
||||
console.log(value)
|
||||
this.form.setFieldsValue({
|
||||
note: `Hi, ${value === 'male' ? 'man' : 'lady'}!`,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -35,6 +35,7 @@ function createBaseForm (option = {}, mixins = []) {
|
||||
fieldDataProp,
|
||||
formPropName = 'form',
|
||||
props = {},
|
||||
templateContext,
|
||||
} = option
|
||||
|
||||
return function decorate (WrappedComponent) {
|
||||
@ -327,7 +328,11 @@ function createBaseForm (option = {}, mixins = []) {
|
||||
.reduce((acc, name) => set(acc, name, this.fieldsStore.getField(name)), {})
|
||||
onFieldsChange(this, changedFields, this.fieldsStore.getNestedAllFields())
|
||||
}
|
||||
this.$forceUpdate()
|
||||
if (templateContext) {
|
||||
templateContext.$forceUpdate()
|
||||
} else {
|
||||
this.$forceUpdate()
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
callback && callback()
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user