Design a Login Form Using Awt Controls
Horizontal login form is often used in navigation bar.
import { Form, Icon, Input, Button, } from 'antd' ; function hasErrors (fieldsError) { return Object. keys (fieldsError) . some (field = > fieldsError[field] ) ; } class HorizontalLoginForm extends React.Component { componentDidMount ( ) { // To disabled submit button at the beginning. this .props.form. validateFields ( ) ; } handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } render ( ) { const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched, } = this .props.form; // Only show error after a field is touched. const userNameError = isFieldTouched ( 'userName' ) && getFieldError ( 'userName' ) ; const passwordError = isFieldTouched ( 'password' ) && getFieldError ( 'password' ) ; return ( <Form layout = "inline" onSubmit = { this .handleSubmit} > <Form.Item validateStatus = {userNameError ? 'error' : '' } help = {userNameError || '' } > { getFieldDecorator ( 'userName' , { rules: [ { required: true , message: 'Please input your username!' } ] , } ) ( <Input prefix = { <Icon type= "user" style= { { color: 'rgba(0,0,0,.25)' } } /> } placeholder= "Username" / > ) } </Form.Item > <Form.Item validateStatus = {passwordError ? 'error' : '' } help = {passwordError || '' } > { getFieldDecorator ( 'password' , { rules: [ { required: true , message: 'Please input your Password!' } ] , } ) ( <Input prefix = { <Icon type= "lock" style= { { color: 'rgba(0,0,0,.25)' } } /> } type= "password" placeholder= "Password" / > ) } </Form.Item > <Form.Item > <Button type = "primary" htmlType = "submit" disabled = { hasErrors ( getFieldsError ( ) ) } > Log in </Button > </Form.Item > </Form > ) ; } } const WrappedHorizontalLoginForm = Form. create ( { name: 'horizontal_login' } ) (HorizontalLoginForm) ; ReactDOM. render ( <WrappedHorizontalLoginForm /> , mountNode) ;
Normal login form which can contain more elements.
import { Form, Icon, Input, Button, Checkbox, } from 'antd' ; class NormalLoginForm extends React.Component { handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } render ( ) { const { getFieldDecorator } = this .props.form; return ( <Form onSubmit = { this .handleSubmit} className = "login-form" > <Form.Item > { getFieldDecorator ( 'userName' , { rules: [ { required: true , message: 'Please input your username!' } ] , } ) ( <Input prefix = { <Icon type= "user" style= { { color: 'rgba(0,0,0,.25)' } } /> } placeholder= "Username" / > ) } </Form.Item > <Form.Item > { getFieldDecorator ( 'password' , { rules: [ { required: true , message: 'Please input your Password!' } ] , } ) ( <Input prefix = { <Icon type= "lock" style= { { color: 'rgba(0,0,0,.25)' } } /> } type= "password" placeholder= "Password" / > ) } </Form.Item > <Form.Item > { getFieldDecorator ( 'remember' , { valuePropName: 'checked' , initialValue: true , } ) ( <Checkbox > Remember me </Checkbox > ) } <a className = "login-form-forgot" href = " " > Forgot password </a > <Button type = "primary" htmlType = "submit" className = "login-form-button" > Log in </Button > Or <a href = " " > register now! </a > </Form.Item > </Form > ) ; } } const WrappedNormalLoginForm = Form. create ( { name: 'normal_login' } ) (NormalLoginForm) ; ReactDOM. render ( <WrappedNormalLoginForm /> , mountNode) ;
#components-form-demo-normal-login .login-form { max-width : 300px; } #components-form-demo-normal-login .login-form-forgot { float : right; } #components-form-demo-normal-login .login-form-button { width : 100% ; }
Fill in this form to create a new account for you.
import { Form, Input, Tooltip, Icon, Cascader, Select, Row, Col, Checkbox, Button, AutoComplete, } from 'antd' ; const { Option } = Select; const AutoCompleteOption = AutoComplete.Option; const residences = [ { value: 'zhejiang' , label: 'Zhejiang' , children: [ { value: 'hangzhou' , label: 'Hangzhou' , children: [ { value: 'xihu' , label: 'West Lake' , } ] , } ] , } , { value: 'jiangsu' , label: 'Jiangsu' , children: [ { value: 'nanjing' , label: 'Nanjing' , children: [ { value: 'zhonghuamen' , label: 'Zhong Hua Men' , } ] , } ] , } ] ; class RegistrationForm extends React.Component { state = { confirmDirty: false , autoCompleteResult: [ ] , } ; handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFieldsAndScroll ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } handleConfirmBlur = (e) = > { const value = e.target.value; this . setState ( { confirmDirty: this .state.confirmDirty || ! !value } ) ; } compareToFirstPassword = (rule, value, callback) = > { const form = this .props.form; if (value && value !== form. getFieldValue ( 'password' ) ) { callback ( 'Two passwords that you enter is inconsistent!' ) ; } else { callback ( ) ; } } validateToNextPassword = (rule, value, callback) = > { const form = this .props.form; if (value && this .state.confirmDirty) { form. validateFields ( [ 'confirm' ] , { force: true } ) ; } callback ( ) ; } handleWebsiteChange = (value) = > { let autoCompleteResult; if ( !value) { autoCompleteResult = [ ] ; } else { autoCompleteResult = [ '.com' , '.org' , '.net' ] . map (domain = > ` ${value} ${domain} ` ) ; } this . setState ( { autoCompleteResult } ) ; } render ( ) { const { getFieldDecorator } = this .props.form; const { autoCompleteResult } = this .state; const formItemLayout = { labelCol: { xs: { span: 24 } , sm: { span: 8 } , } , wrapperCol: { xs: { span: 24 } , sm: { span: 16 } , } , } ; const tailFormItemLayout = { wrapperCol: { xs: { span: 24 , offset: 0 , } , sm: { span: 16 , offset: 8 , } , } , } ; const prefixSelector = getFieldDecorator ( 'prefix' , { initialValue: '86' , } ) ( <Select style = { { width: 70 } } > <Option value = "86" > + 86 </Option > <Option value = "87" > + 87 </Option > </Select > ) ; const websiteOptions = autoCompleteResult. map (website = > ( <AutoCompleteOption key = {website} > {website} </AutoCompleteOption > ) ) ; return ( <Form onSubmit = { this .handleSubmit} > <Form.Item { ...formItemLayout} label= "E-mail" > { getFieldDecorator ( 'email' , { rules: [ { type: 'email' , message: 'The input is not valid E-mail!' , } , { required: true , message: 'Please input your E-mail!' , } ] , } ) ( <Input /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Password" > { getFieldDecorator ( 'password' , { rules: [ { required: true , message: 'Please input your password!' , } , { validator: this .validateToNextPassword, } ] , } ) ( <Input type = "password" /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Confirm Password" > { getFieldDecorator ( 'confirm' , { rules: [ { required: true , message: 'Please confirm your password!' , } , { validator: this .compareToFirstPassword, } ] , } ) ( <Input type = "password" onBlur = { this .handleConfirmBlur} /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= { ( <span > Nickname <Tooltip title = "What do you want others to call you?" > <Icon type = "question-circle-o" /> </Tooltip > </span > ) } > { getFieldDecorator ( 'nickname' , { rules: [ { required: true , message: 'Please input your nickname!' , whitespace: true } ] , } ) ( <Input /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Habitual Residence" > { getFieldDecorator ( 'residence' , { initialValue: [ 'zhejiang' , 'hangzhou' , 'xihu' ] , rules: [ { type: 'array' , required: true , message: 'Please select your habitual residence!' } ] , } ) ( <Cascader options = {residences} /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Phone Number" > { getFieldDecorator ( 'phone' , { rules: [ { required: true , message: 'Please input your phone number!' } ] , } ) ( <Input addonBefore = {prefixSelector} style = { { width: '100%' } } /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Website" > { getFieldDecorator ( 'website' , { rules: [ { required: true , message: 'Please input website!' } ] , } ) ( <AutoComplete dataSource = {websiteOptions} onChange = { this .handleWebsiteChange} placeholder = "website" > <Input /> </AutoComplete > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Captcha" extra= "We must make sure that your are a human." > <Row gutter = { 8 } > <Col span = { 12 } > { getFieldDecorator ( 'captcha' , { rules: [ { required: true , message: 'Please input the captcha you got!' } ] , } ) ( <Input /> ) } </Col > <Col span = { 12 } > <Button > Get captcha </Button > </Col > </Row > </Form.Item > <Form.Item { ...tailFormItemLayout} > { getFieldDecorator ( 'agreement' , { valuePropName: 'checked' , } ) ( <Checkbox > I have read the <a href = " " > agreement </a > </Checkbox > ) } </Form.Item > <Form.Item { ...tailFormItemLayout} > <Button type = "primary" htmlType = "submit" > Register </Button > </Form.Item > </Form > ) ; } } const WrappedRegistrationForm = Form. create ( { name: 'register' } ) (RegistrationForm) ; ReactDOM. render ( <WrappedRegistrationForm /> , mountNode) ;
Three columns layout is often used for advanced searching of data table.
Because the width of label is not fixed, you may need to adjust it by customizing its style.
import { Form, Row, Col, Input, Button, Icon, } from 'antd' ; class AdvancedSearchForm extends React.Component { state = { expand: false , } ; // To generate mock Form.Item getFields ( ) { const count = this .state.expand ? 10 : 6 ; const { getFieldDecorator } = this .props.form; const children = [ ] ; for ( let i = 0 ; i < 10 ; i++ ) { children. push ( <Col span = { 8 } key = {i} style = { { display: i < count ? 'block' : 'none' } } > <Form.Item label = { `Field ${i} ` } > { getFieldDecorator ( `field- ${i} ` , { rules: [ { required: true , message: 'Input something!' , } ] , } ) ( <Input placeholder = "placeholder" /> ) } </Form.Item > </Col > ) ; } return children; } handleSearch = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { console. log ( 'Received values of form: ' , values) ; } ) ; } handleReset = ( ) = > { this .props.form. resetFields ( ) ; } toggle = ( ) = > { const { expand } = this .state; this . setState ( { expand: !expand } ) ; } render ( ) { return ( <Form className = "ant-advanced-search-form" onSubmit = { this .handleSearch} > <Row gutter = { 24 } > { this . getFields ( ) } </Row > <Row > <Col span = { 24 } style = { { textAlign: 'right' } } > <Button type = "primary" htmlType = "submit" > Search </Button > <Button style = { { marginLeft: 8 } } onClick = { this .handleReset} > Clear </Button > <a style = { { marginLeft: 8 , fontSize: 12 } } onClick = { this .toggle} > Collapse <Icon type = { this .state.expand ? 'up' : 'down' } /> </a > </Col > </Row > </Form > ) ; } } const WrappedAdvancedSearchForm = Form. create ( { name: 'advanced_search' } ) (AdvancedSearchForm) ; ReactDOM. render ( <div > <WrappedAdvancedSearchForm /> <div className = "search-result-list" > Search Result List </div > </div > , mountNode ) ;
.ant-advanced-search-form { padding : 24px; background : #fbfbfb ; border : 1px solid #d9d9d9 ; border-radius : 6px; } .ant-advanced-search-form .ant-form-item { display : flex; } .ant-advanced-search-form .ant-form-item-control-wrapper { flex : 1 ; }
When user visit a page with a list of items, and want to create a new item. The page can popup a form in Modal, then let user fill in the form to create an item.
import { Button, Modal, Form, Input, Radio, } from 'antd' ; const CollectionCreateForm = Form. create ( { name: 'form_in_modal' } ) ( // eslint-disable-next-line class extends React.Component { render ( ) { const { visible, onCancel, onCreate, form, } = this .props; const { getFieldDecorator } = form; return ( <Modal visible = {visible} title = "Create a new collection" okText = "Create" onCancel = {onCancel} onOk = {onCreate} > <Form layout = "vertical" > <Form.Item label = "Title" > { getFieldDecorator ( 'title' , { rules: [ { required: true , message: 'Please input the title of collection!' } ] , } ) ( <Input /> ) } </Form.Item > <Form.Item label = "Description" > { getFieldDecorator ( 'description' ) ( <Input type = "textarea" /> ) } </Form.Item > <Form.Item className = "collection-create-form_last-form-item" > { getFieldDecorator ( 'modifier' , { initialValue: 'public' , } ) ( <Radio.Group > <Radio value = "public" > Public </Radio > <Radio value = "private" > Private </Radio > </Radio.Group > ) } </Form.Item > </Form > </Modal > ) ; } } ) ; class CollectionsPage extends React.Component { state = { visible: false , } ; showModal = ( ) = > { this . setState ( { visible: true } ) ; } handleCancel = ( ) = > { this . setState ( { visible: false } ) ; } handleCreate = ( ) = > { const form = this .formRef.props.form; form. validateFields ( (err, values) = > { if (err) { return ; } console. log ( 'Received values of form: ' , values) ; form. resetFields ( ) ; this . setState ( { visible: false } ) ; } ) ; } saveFormRef = (formRef) = > { this .formRef = formRef; } render ( ) { return ( <div > <Button type = "primary" onClick = { this .showModal} > New Collection </Button > <CollectionCreateForm wrappedComponentRef = { this .saveFormRef} visible = { this .state.visible} onCancel = { this .handleCancel} onCreate = { this .handleCreate} /> </div > ) ; } } ReactDOM. render ( <CollectionsPage /> , mountNode) ;
.collection-create-form_last-form-item { margin-bottom : 0 ; }
Add or remove form items dynamically.
import { Form, Input, Icon, Button, } from 'antd' ; let id = 0 ; class DynamicFieldSet extends React.Component { remove = (k) = > { const { form } = this .props; // can use data-binding to get const keys = form. getFieldValue ( 'keys' ) ; // We need at least one passenger if (keys.length === 1 ) { return ; } // can use data-binding to set form. setFieldsValue ( { keys: keys. filter (key = > key !== k) , } ) ; } add = ( ) = > { const { form } = this .props; // can use data-binding to get const keys = form. getFieldValue ( 'keys' ) ; const nextKeys = keys. concat (id++ ) ; // can use data-binding to set // important! notify form to detect changes form. setFieldsValue ( { keys: nextKeys, } ) ; } handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } render ( ) { const { getFieldDecorator, getFieldValue } = this .props.form; const formItemLayout = { labelCol: { xs: { span: 24 } , sm: { span: 4 } , } , wrapperCol: { xs: { span: 24 } , sm: { span: 20 } , } , } ; const formItemLayoutWithOutLabel = { wrapperCol: { xs: { span: 24 , offset: 0 } , sm: { span: 20 , offset: 4 } , } , } ; getFieldDecorator ( 'keys' , { initialValue: [ ] } ) ; const keys = getFieldValue ( 'keys' ) ; const formItems = keys. map ( (k, index) = > ( <Form.Item { ... (index === 0 ? formItemLayout : formItemLayoutWithOutLabel) } label= {index === 0 ? 'Passengers' : '' } required= { false } key= {k} > { getFieldDecorator ( `names[ ${k} ]` , { validateTrigger: [ 'onChange' , 'onBlur' ] , rules: [ { required: true , whitespace: true , message: "Please input passenger's name or delete this field." , } ] , } ) ( <Input placeholder = "passenger name" style = { { width: '60%' , marginRight: 8 } } /> ) } {keys.length > 1 ? ( <Icon className = "dynamic-delete-button" type = "minus-circle-o" disabled = {keys.length === 1 } onClick = { ( ) = > this . remove (k) } /> ) : null } </Form.Item > ) ) ; return ( <Form onSubmit = { this .handleSubmit} > {formItems} <Form.Item { ...formItemLayoutWithOutLabel} > <Button type = "dashed" onClick = { this .add} style = { { width: '60%' } } > <Icon type = "plus" /> Add field </Button > </Form.Item > <Form.Item { ...formItemLayoutWithOutLabel} > <Button type = "primary" htmlType = "submit" > Submit </Button > </Form.Item > </Form > ) ; } } const WrappedDynamicFieldSet = Form. create ( { name: 'dynamic_form_item' } ) (DynamicFieldSet) ; ReactDOM. render ( <WrappedDynamicFieldSet /> , mountNode) ;
.dynamic-delete-button { cursor : pointer; position : relative; top : 4px; font-size : 24px; color : #999 ; transition : all .3s; } .dynamic-delete-button :hover { color : #777 ; } .dynamic-delete-button [disabled] { cursor : not-allowed; opacity : 0.5 ; }
Customized or third-party form controls can be used in Form, too. Controls must follow these conventions:
It has a controlled property
value
or other name which is equal to the value ofvaluePropName
.It has event
onChange
or an event which name is equal to the value oftrigger
.It must be a class component.
import { Form, Input, Select, Button, } from 'antd' ; const { Option } = Select; class PriceInput extends React.Component { static getDerivedStateFromProps (nextProps) { // Should be a controlled component. if ( 'value' in nextProps) { return { ... (nextProps.value || { } ) , } ; } return null ; } constructor (props) { super (props) ; const value = props.value || { } ; this .state = { number: value.number || 0 , currency: value.currency || 'rmb' , } ; } handleNumberChange = (e) = > { const number = parseInt (e.target.value || 0 , 10 ) ; if (Number. isNaN (number) ) { return ; } if ( ! ( 'value' in this .props) ) { this . setState ( { number } ) ; } this . triggerChange ( { number } ) ; } handleCurrencyChange = (currency) = > { if ( ! ( 'value' in this .props) ) { this . setState ( { currency } ) ; } this . triggerChange ( { currency } ) ; } triggerChange = (changedValue) = > { // Should provide an event to pass value to Form. const onChange = this .props.onChange; if (onChange) { onChange (Object. assign ( { } , this .state, changedValue) ) ; } } render ( ) { const { size } = this .props; const state = this .state; return ( <span > <Input type = "text" size = {size} value = {state.number} onChange = { this .handleNumberChange} style = { { width: '65%' , marginRight: '3%' } } /> <Select value = {state.currency} size = {size} style = { { width: '32%' } } onChange = { this .handleCurrencyChange} > <Option value = "rmb" > RMB </Option > <Option value = "dollar" > Dollar </Option > </Select > </span > ) ; } } class Demo extends React.Component { handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } checkPrice = (rule, value, callback) = > { if (value.number > 0 ) { callback ( ) ; return ; } callback ( 'Price must greater than zero!' ) ; } render ( ) { const { getFieldDecorator } = this .props.form; return ( <Form layout = "inline" onSubmit = { this .handleSubmit} > <Form.Item label = "Price" > { getFieldDecorator ( 'price' , { initialValue: { number: 0 , currency: 'rmb' } , rules: [ { validator: this .checkPrice } ] , } ) ( <PriceInput /> ) } </Form.Item > <Form.Item > <Button type = "primary" htmlType = "submit" > Submit </Button > </Form.Item > </Form > ) ; } } const WrappedDemo = Form. create ( { name: 'customized_form_controls' } ) (Demo) ; ReactDOM. render ( <WrappedDemo /> , mountNode) ;
{ "username": { "value": "benjycui" } }
We can store form data into upper component or Redux or dva by using onFieldsChange
and mapPropsToFields
, see more at this rc-form demo.
Note: You must wrap field data with Form.createFormField
in mapPropsToFields
.
import { Form, Input } from 'antd' ; const CustomizedForm = Form. create ( { name: 'global_state' , onFieldsChange (props, changedFields) { props. onChange (changedFields) ; } , mapPropsToFields (props) { return { username: Form. createFormField ( { ...props.username, value: props.username.value, } ) , } ; } , onValuesChange (_, values) { console. log (values) ; } , } ) ( (props) = > { const { getFieldDecorator } = props.form; return ( <Form layout = "inline" > <Form.Item label = "Username" > { getFieldDecorator ( 'username' , { rules: [ { required: true , message: 'Username is required!' } ] , } ) ( <Input /> ) } </Form.Item > </Form > ) ; } ) ; class Demo extends React.Component { state = { fields: { username: { value: 'benjycui' , } , } , } ; handleFormChange = (changedFields) = > { this . setState ( ( { fields } ) = > ( { fields: { ...fields, ...changedFields } , } ) ) ; } render ( ) { const fields = this .state.fields; return ( <div > <CustomizedForm { ...fields} onChange= { this .handleFormChange} / > <pre className = "language-bash" > {JSON. stringify (fields, null , 2 ) } </pre > </div > ) ; } } ReactDOM. render ( <Demo /> , mountNode) ;
Form.create
will collect and validate form data automatically. But if you don't need this feature or the default behaviour cannot satisfy your business, you can drop Form.create
and handle form data manually.
import { Form, InputNumber } from 'antd' ; function validatePrimeNumber (number) { if (number === 11 ) { return { validateStatus: 'success' , errorMsg: null , } ; } return { validateStatus: 'error' , errorMsg: 'The prime between 8 and 12 is 11!' , } ; } class RawForm extends React.Component { state = { number: { value: 11 , } , } ; handleNumberChange = (value) = > { this . setState ( { number: { ... validatePrimeNumber (value) , value, } , } ) ; } render ( ) { const formItemLayout = { labelCol: { span: 7 } , wrapperCol: { span: 12 } , } ; const number = this .state.number; const tips = 'A prime is a natural number greater than 1 that has no positive divisors other than 1 and itself.' ; return ( <Form > <Form.Item { ...formItemLayout} label= "Prime between 8 & 12" validateStatus= {number.validateStatus} help= {number.errorMsg || tips} > <InputNumber min = { 8 } max = { 12 } value = {number.value} onChange = { this .handleNumberChange} /> </Form.Item > </Form > ) ; } } ReactDOM. render ( <RawForm /> , mountNode) ;
We provide properties like validateStatus
help
hasFeedback
to customize your own validate status and message, without using Form.create
and getFieldDecorator
.
-
validateStatus
: validate status of form components which could be 'success', 'warning', 'error', 'validating'. -
hasFeedback
: display feed icon of input control -
help
: display validate message.
import { Form, Input, DatePicker, TimePicker, Select, Cascader, InputNumber, } from 'antd' ; const { Option } = Select; const formItemLayout = { labelCol: { xs: { span: 24 } , sm: { span: 5 } , } , wrapperCol: { xs: { span: 24 } , sm: { span: 12 } , } , } ; ReactDOM. render ( <Form > <Form.Item { ...formItemLayout} label= "Fail" validateStatus= "error" help= "Should be combination of numbers & alphabets" > <Input placeholder = "unavailable choice" id = "error" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Warning" validateStatus= "warning" > <Input placeholder = "Warning" id = "warning" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Validating" hasFeedback validateStatus= "validating" help= "The information is being validated..." > <Input placeholder = "I'm the content is being validated" id = "validating" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Success" hasFeedback validateStatus= "success" > <Input placeholder = "I'm the content" id = "success" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Warning" hasFeedback validateStatus= "warning" > <Input placeholder = "Warning" id = "warning2" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Fail" hasFeedback validateStatus= "error" help= "Should be combination of numbers & alphabets" > <Input placeholder = "unavailable choice" id = "error2" /> </Form.Item > <Form.Item { ...formItemLayout} label= "Success" hasFeedback validateStatus= "success" > <DatePicker style = { { width: '100%' } } /> </Form.Item > <Form.Item { ...formItemLayout} label= "Warning" hasFeedback validateStatus= "warning" > <TimePicker style = { { width: '100%' } } /> </Form.Item > <Form.Item { ...formItemLayout} label= "Error" hasFeedback validateStatus= "error" > <Select defaultValue = "1" > <Option value = "1" > Option 1 </Option > <Option value = "2" > Option 2 </Option > <Option value = "3" > Option 3 </Option > </Select > </Form.Item > <Form.Item { ...formItemLayout} label= "Validating" hasFeedback validateStatus= "validating" help= "The information is being validated..." > <Cascader defaultValue = { [ '1' ] } options = { [ ] } /> </Form.Item > <Form.Item label = "inline" {...formItemLayout} style = { { marginBottom: 0 } } > <Form.Item validateStatus = "error" help = "Please select the correct date" style = { { display: 'inline-block' , width: 'calc(50% - 12px)' } } > <DatePicker /> </Form.Item > <span style = { { display: 'inline-block' , width: '24px' , textAlign: 'center' } } > - </span > <Form.Item style = { { display: 'inline-block' , width: 'calc(50% - 12px)' } } > <DatePicker /> </Form.Item > </Form.Item > <Form.Item { ...formItemLayout} label= "Success" hasFeedback validateStatus= "success" > <InputNumber style = { { width: '100%' } } /> </Form.Item > </Form > , mountNode ) ;
Use setFieldsValue
to set other control's value programmaticly.
import { Form, Select, Input, Button, } from 'antd' ; const { Option } = Select; class App extends React.Component { handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } handleSelectChange = (value) = > { console. log (value) ; this .props.form. setFieldsValue ( { note: `Hi, ${value === 'male' ? 'man' : 'lady' } !` , } ) ; } render ( ) { const { getFieldDecorator } = this .props.form; return ( <Form onSubmit = { this .handleSubmit} > <Form.Item label = "Note" labelCol = { { span: 5 } } wrapperCol = { { span: 12 } } > { getFieldDecorator ( 'note' , { rules: [ { required: true , message: 'Please input your note!' } ] , } ) ( <Input /> ) } </Form.Item > <Form.Item label = "Gender" labelCol = { { span: 5 } } wrapperCol = { { span: 12 } } > { getFieldDecorator ( 'gender' , { rules: [ { required: true , message: 'Please select your gender!' } ] , } ) ( <Select placeholder = "Select a option and change input text above" onChange = { this .handleSelectChange} > <Option value = "male" > male </Option > <Option value = "female" > female </Option > </Select > ) } </Form.Item > <Form.Item wrapperCol = { { span: 12 , offset: 5 } } > <Button type = "primary" htmlType = "submit" > Submit </Button > </Form.Item > </Form > ) ; } } const WrappedApp = Form. create ( { name: 'coordinated' } ) (App) ; ReactDOM. render ( <WrappedApp /> , mountNode) ;
There are three layout for form: horizontal
, vertical
, inline
.
import { Form, Input, Button, Radio, } from 'antd' ; class FormLayoutDemo extends React.Component { constructor ( ) { super ( ) ; this .state = { formLayout: 'horizontal' , } ; } handleFormLayoutChange = (e) = > { this . setState ( { formLayout: e.target.value } ) ; } render ( ) { const { formLayout } = this .state; const formItemLayout = formLayout === 'horizontal' ? { labelCol: { span: 4 } , wrapperCol: { span: 14 } , } : null ; const buttonItemLayout = formLayout === 'horizontal' ? { wrapperCol: { span: 14 , offset: 4 } , } : null ; return ( <div > <Form layout = {formLayout} > <Form.Item label = "Form Layout" {...formItemLayout} > <Radio.Group defaultValue = "horizontal" onChange = { this .handleFormLayoutChange} > <Radio.Button value = "horizontal" > Horizontal </Radio.Button > <Radio.Button value = "vertical" > Vertical </Radio.Button > <Radio.Button value = "inline" > Inline </Radio.Button > </Radio.Group > </Form.Item > <Form.Item label = "Field A" {...formItemLayout} > <Input placeholder = "input placeholder" /> </Form.Item > <Form.Item label = "Field B" {...formItemLayout} > <Input placeholder = "input placeholder" /> </Form.Item > <Form.Item { ...buttonItemLayout} > <Button type = "primary" > Submit </Button > </Form.Item > </Form > </div > ) ; } } ReactDOM. render ( <FormLayoutDemo /> , mountNode) ;
Perform different check rules according to different situations.
import { Form, Input, Button, Checkbox, } from 'antd' ; const formItemLayout = { labelCol: { span: 4 } , wrapperCol: { span: 8 } , } ; const formTailLayout = { labelCol: { span: 4 } , wrapperCol: { span: 8 , offset: 4 } , } ; class DynamicRule extends React.Component { state = { checkNick: false , } ; check = ( ) = > { this .props.form. validateFields ( (err) = > { if ( !err) { console. info ( 'success' ) ; } } , ) ; } handleChange = (e) = > { this . setState ( { checkNick: e.target.checked, } , ( ) = > { this .props.form. validateFields ( [ 'nickname' ] , { force: true } ) ; } ) ; } render ( ) { const { getFieldDecorator } = this .props.form; return ( <div > <Form.Item { ...formItemLayout} label= "Name" > { getFieldDecorator ( 'username' , { rules: [ { required: true , message: 'Please input your name' , } ] , } ) ( <Input placeholder = "Please input your name" /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Nickname" > { getFieldDecorator ( 'nickname' , { rules: [ { required: this .state.checkNick, message: 'Please input your nickname' , } ] , } ) ( <Input placeholder = "Please input your nickname" /> ) } </Form.Item > <Form.Item { ...formTailLayout} > <Checkbox checked = { this .state.checkNick} onChange = { this .handleChange} > Nickname is required </Checkbox > </Form.Item > <Form.Item { ...formTailLayout} > <Button type = "primary" onClick = { this .check} > Check </Button > </Form.Item > </div > ) ; } } const WrappedDynamicRule = Form. create ( { name: 'dynamic_rule' } ) (DynamicRule) ; ReactDOM. render ( <WrappedDynamicRule /> , mountNode) ;
Demonstration of validation configuration for form controls which are not shown in the demos above.
import { Form, Select, InputNumber, Switch, Radio, Slider, Button, Upload, Icon, Rate, Checkbox, Row, Col, } from 'antd' ; const { Option } = Select; class Demo extends React.Component { handleSubmit = (e) = > { e. preventDefault ( ) ; this .props.form. validateFields ( (err, values) = > { if ( !err) { console. log ( 'Received values of form: ' , values) ; } } ) ; } normFile = (e) = > { console. log ( 'Upload event:' , e) ; if (Array. isArray (e) ) { return e; } return e && e.fileList; } render ( ) { const { getFieldDecorator } = this .props.form; const formItemLayout = { labelCol: { span: 6 } , wrapperCol: { span: 14 } , } ; return ( <Form onSubmit = { this .handleSubmit} > <Form.Item { ...formItemLayout} label= "Plain Text" > <span className = "ant-form-text" > China </span > </Form.Item > <Form.Item { ...formItemLayout} label= "Select" hasFeedback > { getFieldDecorator ( 'select' , { rules: [ { required: true , message: 'Please select your country!' } , ] , } ) ( <Select placeholder = "Please select a country" > <Option value = "china" > China </Option > <Option value = "usa" > U.S.A </Option > </Select > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Select[multiple]" > { getFieldDecorator ( 'select-multiple' , { rules: [ { required: true , message: 'Please select your favourite colors!' , type: 'array' } , ] , } ) ( <Select mode = "multiple" placeholder = "Please select favourite colors" > <Option value = "red" > Red </Option > <Option value = "green" > Green </Option > <Option value = "blue" > Blue </Option > </Select > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "InputNumber" > { getFieldDecorator ( 'input-number' , { initialValue: 3 } ) ( <InputNumber min = { 1 } max = { 10 } /> ) } <span className = "ant-form-text" > machines </span > </Form.Item > <Form.Item { ...formItemLayout} label= "Switch" > { getFieldDecorator ( 'switch' , { valuePropName: 'checked' } ) ( <Switch /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Slider" > { getFieldDecorator ( 'slider' ) ( <Slider marks = { { 0 : 'A' , 20 : 'B' , 40 : 'C' , 60 : 'D' , 80 : 'E' , 100 : 'F' , } } /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Radio.Group" > { getFieldDecorator ( 'radio-group' ) ( <Radio.Group > <Radio value = "a" > item 1 </Radio > <Radio value = "b" > item 2 </Radio > <Radio value = "c" > item 3 </Radio > </Radio.Group > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Radio.Button" > { getFieldDecorator ( 'radio-button' ) ( <Radio.Group > <Radio.Button value = "a" > item 1 </Radio.Button > <Radio.Button value = "b" > item 2 </Radio.Button > <Radio.Button value = "c" > item 3 </Radio.Button > </Radio.Group > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Checkbox.Group" > { getFieldDecorator ( "checkbox-group" , { initialValue: [ "A" , "B" ] , } ) ( <Checkbox.Group style = { { width: "100%" } } > <Row > <Col span = { 8 } > <Checkbox value = "A" > A </Checkbox > </Col > <Col span = { 8 } > <Checkbox disabled value = "B" > B </Checkbox > </Col > <Col span = { 8 } > <Checkbox value = "C" > C </Checkbox > </Col > <Col span = { 8 } > <Checkbox value = "D" > D </Checkbox > </Col > <Col span = { 8 } > <Checkbox value = "E" > E </Checkbox > </Col > </Row > </Checkbox.Group > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Rate" > { getFieldDecorator ( 'rate' , { initialValue: 3.5 , } ) ( <Rate /> ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Upload" extra= "longgggggggggggggggggggggggggggggggggg" > { getFieldDecorator ( 'upload' , { valuePropName: 'fileList' , getValueFromEvent: this .normFile, } ) ( <Upload name = "logo" action = "/upload.do" listType = "picture" > <Button > <Icon type = "upload" /> Click to upload </Button > </Upload > ) } </Form.Item > <Form.Item { ...formItemLayout} label= "Dragger" > <div className = "dropbox" > { getFieldDecorator ( 'dragger' , { valuePropName: 'fileList' , getValueFromEvent: this .normFile, } ) ( <Upload.Dragger name = "files" action = "/upload.do" > <p className = "ant-upload-drag-icon" > <Icon type = "inbox" /> </p > <p className = "ant-upload-text" > Click or drag file to this area to upload </p > <p className = "ant-upload-hint" > Support for a single or bulk upload. </p > </Upload.Dragger > ) } </div > </Form.Item > <Form.Item wrapperCol = { { span: 12 , offset: 6 } } > <Button type = "primary" htmlType = "submit" > Submit </Button > </Form.Item > </Form > ) ; } } const WrappedDemo = Form. create ( { name: 'validate_other' } ) (Demo) ; ReactDOM. render ( <WrappedDemo /> , mountNode) ;
#components-form-demo-validate-other .dropbox { height : 180px; line-height : 1.5 ; }
API#
Form#
more example rc-form。
Property | Description | Type | Default Value |
---|---|---|---|
form | Decorated by Form.create() will be automatically set this.props.form property | object | n/a |
hideRequiredMark | Hide required mark of all form items | Boolean | false |
layout | Define form layout | 'horizontal' | 'vertical' | 'inline' | 'horizontal' |
onSubmit | Defines a function will be called if form data validation is successful. | Function(e:Event) |
Form.create(options)#
How to use:
class CustomizedForm extends React.Component { } CustomizedForm = Form. create ( { } ) (CustomizedForm) ;
The following options
are available:
Property | Description | Type |
---|---|---|
mapPropsToFields | Convert props to field value(e.g. reading the values from Redux store). And you must mark returned fields with Form.createFormField | (props) => ({ [ fieldName ] : FormField { value } }) |
name | Set the id prefix of fields under form | - |
validateMessages | Default validate message. And its format is similar with newMessages's returned value | Object { [ nested.path]: String } |
onFieldsChange | Specify a function that will be called when the value a Form.Item gets changed. Usage example: saving the field's value to Redux store. | Function(props, fields) |
onValuesChange | A handler while value of any field is changed | (props, changedValues, allValues) => void |
If you want to get ref
after Form.create
, you can use wrappedComponentRef
provided by rc-form
, details can be viewed here.
class CustomizedForm extends React.Component { ... } // use wrappedComponentRef const EnhancedForm = Form. create ( ) (CustomizedForm) ; <EnhancedForm wrappedComponentRef = { (form) = > this .form = form} /> this .form // => The instance of CustomizedForm
If the form has been decorated by Form.create
then it has this.props.form
property. this.props.form
provides some APIs as follows:
Note: Before using
getFieldsValue
getFieldValue
setFieldsValue
and so on, please make sure that corresponding field had been registered withgetFieldDecorator
.
Method | Description | Type |
---|---|---|
getFieldDecorator | Two-way binding for form, please read below for details. | |
getFieldError | Get the error of a field. | Function(name) |
getFieldsError | Get the specified fields' error. If you don't specify a parameter, you will get all fields' error. | Function( [ names: string [ ]]) |
getFieldsValue | Get the specified fields' values. If you don't specify a parameter, you will get all fields' values. | Function( [ fieldNames: string [ ]]) |
getFieldValue | Get the value of a field. | Function(fieldName: string) |
isFieldsTouched | Check whether any of fields is touched by getFieldDecorator 's options.trigger event | (names?: string [ ]) => boolean |
isFieldTouched | Check whether a field is touched by getFieldDecorator 's options.trigger event | (name: string) => boolean |
isFieldValidating | Check if the specified field is being validated. | Function(name) |
resetFields | Reset the specified fields' value(to initialValue ) and status. If you don't specify a parameter, all the fields will be reset. | Function( [ names: string [ ]]) |
setFields | Set value and error state of fields. Code Sample | ({ [ fieldName ] : {value: any, errors: [ Error ] } }) => void |
setFieldsValue | Set the value of a field. (Note: please don't use it in componentWillReceiveProps , otherwise, it will cause an endless loop, reason) | ({ [ fieldName ] : value }) => void |
validateFields | Validate the specified fields and get theirs values and errors. If you don't specify the parameter of fieldNames, you will validate all fields. | ( [ fieldNames: string [ ]], [ options: object ] , callback(errors, values) ) => void |
validateFieldsAndScroll | This function is similar to validateFields , but after validation, if the target field is not in visible area of form, form will be automatically scrolled to the target field area. | same as validateFields |
validateFields/validateFieldsAndScroll#
const { form: { validateFields } } = this .props; validateFields ( (errors, values) = > { // ... } ) ; validateFields ( [ 'field1' , 'field2' ] , (errors, values) = > { // ... } ) ; validateFields ( [ 'field1' , 'field2' ] , options, (errors, values) = > { // ... } ) ;
Method | Description | Type | Default |
---|---|---|---|
options.first | If true , every field will stop validation at first failed rule | boolean | false |
options.firstFields | Those fields will stop validation at first failed rule | String [ ] | [ ] |
options.force | Should validate validated field again when validateTrigger is been triggered again | boolean | false |
options.scroll | Config scroll behavior of validateFieldsAndScroll , more: dom-scroll-into-view's config | Object | {} |
Callback arguments example of validateFields#
-
errors
:{ "userName" : { "errors" : [ { "message" : "Please input your username!" , "field" : "userName" } ] } , "password" : { "errors" : [ { "message" : "Please input your Password!" , "field" : "password" } ] } }
-
values
:{ "userName" : "username" , "password" : "password" , }
Form.createFormField#
To mark the returned fields data in mapPropsToFields
, demo.
this.props.form.getFieldDecorator(id, options)#
After wrapped by getFieldDecorator
, value
(or other property defined by valuePropName
) onChange
(or other property defined by trigger
) props will be added to form controls, the flow of form data will be handled by Form which will cause:
-
You shouldn't use
onChange
to collect data, but you still can listen toonChange
(and so on) events. -
You cannot set value of form control via
value
defaultValue
prop, and you should set default value withinitialValue
ingetFieldDecorator
instead. -
You shouldn't call
setState
manually, please usethis.props.form.setFieldsValue
to change value programmatically.
Special attention#
-
getFieldDecorator
can not be used to decorate stateless component. -
If you use
react@<15.3.0
, then, you can't usegetFieldDecorator
in stateless component: https://github.com/facebook/react/pull/6534
getFieldDecorator(id, options) parameters#
Property | Description | Type | Default Value |
---|---|---|---|
id | The unique identifier is required. support nested fields format. | string | |
options.getValueFromEvent | Specify how to get value from event or other onChange arguments | function(..args) | reference |
options.getValueProps | Get the component props according to field value. | function(value): any | reference |
options.initialValue | You can specify initial value, type, optional value of children node. (Note: Because Form will test equality with === internally, we recommend to use variable as initialValue , instead of literal) | n/a | |
options.normalize | Normalize value to form component, a select-all example | function(value, prevValue, allValues): any | - |
options.preserve | Keep the field even if field removed | boolean | - |
options.rules | Includes validation rules. Please refer to "Validation Rules" part for details. | object [ ] | n/a |
options.trigger | When to collect the value of children node | string | 'onChange' |
options.validateFirst | Whether stop validate on first rule of error for this field. | boolean | false |
options.validateTrigger | When to validate the value of children node. | string | string [ ] | 'onChange' |
options.valuePropName | Props of children node, for example, the prop of Switch is 'checked'. | string | 'value' |
More option at rc-form option。
Form.Item#
Note: if Form.Item has multiple children that had been decorated by getFieldDecorator
, help
and required
and validateStatus
can't be generated automatically.
Property | Description | Type | Default Value |
---|---|---|---|
colon | Used with label , whether to display : after label text. | boolean | true |
extra | The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time. | string | ReactNode | |
hasFeedback | Used with validateStatus , this option specifies the validation status icon. Recommended to be used only with Input . | boolean | false |
help | The prompt message. If not provided, the prompt message will be generated by the validation rule. | string | ReactNode | |
label | Label text | string | ReactNode | |
labelCol | The layout of label. You can set span offset to something like {span: 3, offset: 12} or sm: {span: 3, offset: 12} same as with <Col> | object | |
required | Whether provided or not, it will be generated by the validation rule. | boolean | false |
validateStatus | The validation status. If not provided, it will be generated by validation rule. options: 'success' 'warning' 'error' 'validating' | string | |
wrapperCol | The layout for input controls, same as labelCol | object |
Validation Rules#
Property | Description | Type | Default Value |
---|---|---|---|
enum | validate a value from a list of possible values | string | - |
len | validate an exact length of a field | number | - |
max | validate a max length of a field | number | - |
message | validation error message | string | ReactNode | - |
min | validate a min length of a field | number | - |
pattern | validate from a regular expression | RegExp | - |
required | indicates whether field is required | boolean | false |
transform | transform a value before validation | function(value) => transformedValue:any | - |
type | built-in validation type, available options | string | 'string' |
validator | custom validate function (Note: callback must be called) | function(rule, value, callback) | - |
whitespace | treat required fields that only contain whitespace as errors | boolean | false |
See more advanced usage at async-validator.
Using in TypeScript#
import { Form } from 'antd' ; import { FormComponentProps } from 'antd/lib/form' ; interface UserFormProps extends FormComponentProps { age: number; name: string; } class UserForm extends React.Component <UserFormProps, any> { // ... }
Design a Login Form Using Awt Controls
Source: https://gary-shen.github.io/ant-design/components/form/
0 Response to "Design a Login Form Using Awt Controls"
Post a Comment