React Project: Step 8 Form Validation

使Contact中的input+form有效

自定义input(style+type)

Input.js

import React from 'react';
import classes from './Input.css'
const Input = (props)=>{
    let inputElement = null;
    switch(props.inputtype){
        case('input'):
            inputElement=<input className={classes.InputElement} {...props}/>;
            break;
        case('textarea'):
            inputElement=<textarea className={classes.InputElement} {...props}/>;
            break;
        default:
            inputElement=<input className={classes.InputElement} {...props}/>;
    };

    return (
        <div className={classes.Input}>
            <label className={classes.Label}>
                    {props.label}
            </label>
            {inputElement}
        </div>
    )
};

export default Input;

将input放入contactdata.js中

    render(){
        let form=(                
                <form>
                    <Input inputtype="input" type="text" name="name" placeholder="Your name"/>
                    <Input inputtype="input" type="email" name="email" placeholder="Your email"/>
                    <Input inputtype="input" type="text" name="street" placeholder="Street"/>
                    <Input inputtype="input" type="text" name="postal" placeholder="Postak Code"/>
                    <Button 
                        btnType="Success"
                        clicked={this.orderHandler}
                        >ORDER</Button>
                </form>);
        if(this.state.loading){
            form=<Spinner/>;
        }
        return (
            <div className={classes.ContactData}>
                <h4>Enter your Contact Data</h4>
                {form}
            </div>
        );
    }

contactData中设置多个input,动态放入form中

ContactData.js

import React, { Component } from 'react';
import Button from '../../components/UI/Button/Button';
import classes from './ContactData.module.css';
import axios from '../../axios-orders';
import Spinner from '../../components/UI/Spinner/Spinner';
import Input from '../../components/UI/Input/Input';Input

class ContactData extends Component{
    state = {
        orderForm:{
                name: {
                    elementType:'input',
                    elementConfig:{
                        type:'text',
                        placeholder:'Your Name'
                    },
                    value:''
                },
                street: {
                    elementType:'input',
                    elementConfig:{
                        type:'text',
                        placeholder:'Street'
                    },
                    value:''
                },
                zipCode: {
                    elementType:'input',
                    elementConfig:{
                        type:'text',
                        placeholder:'ZIP Code'
                    },
                    value:''
                },
                country: {
                    elementType:'input',
                    elementConfig:{
                        type:'text',
                        placeholder:'Country'
                    },
                    value:''
                },
                email: {
                    elementType:'input',
                    elementConfig:{
                        type:'email',
                        placeholder:'Your E-Mail'
                    },
                    value:''
                },
                deliveryMethod: {
                    elementType:'select',
                    elementConfig:{
                        options:[
                            {value:'fastest',displayValue:'Fastest'},
                            {value:'cheapest',displayValue:'Cheapest'}
                        ]
                    },
                    value:''
                }
        }
        ,loading:false
    }

    orderHandler=(event)=>{
        console.log(this.props.ingredients);
        event.preventDefault();  //放置form事件默认刷新页面
        this.setState( { loading: true } );
        const order = {
            ingredients: this.props.ingredients,
            price: this.props.totalPrice
        }
        axios.post( '/orders.json', order )
            .then( response => {
                this.setState( { loading: false});
                this.props.history.push('/');
            } )
            .catch( error => {
                this.setState( { loading: false} );
            } );
    }

    render(){
        const formElementArray = [];
        for(let key in this.state.orderForm){     //遍历每个name
            formElementArray.push({
                id:key,
                config:this.state.orderForm[key]
            });
        }
        let form=(                
                <form>
                    
                    {formElementArray.map(formElement=>(
                       <Input  
                        key={formElement.id}
                        elementType={formElement.config.elementType} 
                        elementConfig={formElement.config.elementConfig} 
                        value={formElement.config.value}/> 
                    ))}
                    <Button 
                        btnType="Success"
                        clicked={this.orderHandler}
                        >ORDER</Button>
                </form>);
        if(this.state.loading){
            form=<Spinner/>;
        }
        return (
            <div className={classes.ContactData}>
                <h4>Enter your Contact Data</h4>
                {form}
            </div>
        );
    }
};

export default ContactData;

Input.js

import React from 'react';
import classes from './Input.css'
const Input = (props)=>{
    let inputElement = null;
    switch(props.elementType){
        case('input'):
            inputElement=<input 
                className={classes.InputElement} 
                {...props.elementConfig}
                value={props.value}
                />;
            break;
        case('textarea'):
            inputElement=<textarea 
                className={classes.InputElement} 
                {...props.elementConfig}
                value={props.value}
                />;
            break;
        case('select'):
                inputElement=
                <select 
                    className={classes.InputElement} 
                    value={props.value}>
                    {props.elementConfig.options.map(option=>(
                        <option 
                            key={option.value}
                            value={option.value}>
                            {option.displayValue}
                        </option>
                    ))}
                </select>;
            break;
        default:
            inputElement=<input 
                className={classes.InputElement} 
                {...props.elementConfig}
                value={props.value}
                />;
    };

    return (
        <div className={classes.Input}>
            <label className={classes.Label}>
                    {props.label}
            </label>
            {inputElement}
        </div>
    )
};

export default Input;

在Input中加入onchange listener ,用于得到用户的输入

设置input的onchang
input.js

inputElement=<input
                onChange={props.changed}
                className={classes.InputElement} 
                {...props.elementConfig}
                value={props.value}
                />;
            break;

ContactData.js
设置changed传入input;

该函数得到event+id;用于改变state中特定id的内容;

inputChangedHandler = (event, inputIdentifier)=>{       //改变state
        const updatedOrderForm = {   //子类的子类不会被深度拷贝
            ...this.state.orderForm
        };
        const updatedFormElement={
            ...updatedOrderForm[inputIdentifier]
        };   //需要再次深度拷贝
        updatedFormElement.value=event.target.value;
        updatedOrderForm[inputIdentifier]=updatedFormElement;  
        //updatedorderform的内容为深拷贝
        //但updatedOrderForm[inputIdentifier]指向原先state的地址;
        //此举改变其地址指向新地址;
        this.setState({orderForm:updatedOrderForm});
        event.preventDefault();
    }

form中的内容
changed调用该函数,并传入event和id

{formElementArray.map(formElement=>(
                       <Input  
                        key={formElement.id}
                        elementType={formElement.config.elementType} 
                        elementConfig={formElement.config.elementConfig} 
                        value={formElement.config.value}
                        changed={(event)=>this.inputChangedHandler(event,formElement.id)}
                        /> 
                    ))}

two way binding

input中的value为state中的传入;
input中设置onchanged,得到用户输入;
state中的value,随input中onchanged的输入变化;
此为 two way binding

将form上传至database

不在button上设置onclick;
改为在form上设置onSubmit

<form onSubmit={this.orderHandler}>
                    
                    {formElementArray.map(formElement=>(
                       <Input  
                        key={formElement.id}
                        elementType={formElement.config.elementType} 
                        elementConfig={formElement.config.elementConfig} 
                        value={formElement.config.value}
                        changed={(event)=>this.inputChangedHandler(event,formElement.id)}
                        /> 
                    ))}
                    <Button 
                        btnType="Success"
                        >ORDER</Button>
                </form>);

orderhandler函数
设置要上传的data obj;
用for in 将state中的value全部放入obj中;

orderHandler=(event)=>{
        this.setState( { loading: true } );

        const formData = {};
        for(let formElementIdentifier in this.state.orderForm){
            formData[formElementIdentifier] = this.state.orderForm[formElementIdentifier].value;
        };

        const order = {
            ingredients: this.props.ingredients,
            price: this.props.totalPrice,
            orderData:formData
        }
        axios.post( '/orders.json', order )
            .then( response => {
                this.setState( { loading: false});
                this.props.history.push('/');
            } )
            .catch( error => {
                this.setState( { loading: false} );
            } );
        event.preventDefault();  //阻止页面刷新
    }

为Form的输入设置validation

对staet中form的config设置valid与validation参数

name: {
                    elementType:'input',
                    elementConfig:{
                        type:'text',
                        placeholder:'Your Name'
                    },
                    value:'',
                    validation:{
                        required:true
                    },
                    valid:false

valiadation中设置需要验证的内容;
valid中判断是否有效;
判断函数
传入validation和用户的输入value;
取validation中的要求逐个对value进行判断;
返回boolean表示是否有效;

checkValidity(value, rules){
        let isValid= true;
        if(rules.required&&isValid){
            isValid= value.trim()!=='';   //.trim()可以可以防止空格
        }

        if(rules.minLength&&isValid){
            isValid= value.length>=rules.minLength;
        }

        if(rules.maxLength&&isValid){
            isValid= value.length<=rules.maxLength;
        }

        return isValid;
    }

在判断invalid时让input显示红色

input设置class的添加(用于颜色改变)
为input添加classes,若为invalid,则用红色style的css;

    if(props.invalid&& props.shouldValidate){
        inputClasses.push(classes.Invalid);
    }

在ContactData中判断是否valid
在输入后开始判断;
若无validation参数,则无需判断;

判断form中的所有input是否有效

for in 遍历所元素的valid;
并作为state中的一个props;

    inputChangedHandler = (event, inputIdentifier)=>{       //改变state
        const updatedOrderForm = {   //子类的子类不会被深度拷贝
            ...this.state.orderForm
        };
        const updatedFormElement={
            ...updatedOrderForm[inputIdentifier]
        };   //需要再次深度拷贝
        updatedFormElement.value=event.target.value;
        //查看是否valid
        updatedFormElement.valid=this.checkValidity(updatedFormElement.value, updatedFormElement.validation);
        updatedFormElement.touched=true;  //表示更新过——可以开始valid
        updatedOrderForm[inputIdentifier]=updatedFormElement;  
        //updatedorderform的内容为深拷贝
        //但updatedOrderForm[inputIdentifier]指向原先state的地址;
        //此举改变其地址指向新地址;
        
        let formIsValid= true;  //遍历每个valid,看是否全都为true
        for(let inputIdentifiers in updatedOrderForm){
            formIsValid = updatedOrderForm[inputIdentifiers].valid && formIsValid;
        };

        this.setState({orderForm:updatedOrderForm,formIsValid:formIsValid});
        event.preventDefault();
    }

当form中判断有无效input时,将button设为disabled

                    <Button 
                        btnType="Success"
                        disabled={!this.state.formIsValid}
                        >ORDER</Button>

同时设置button的disabled的cssstyle,即可

.Button:disabled{
    color:#ccc;
    cursor:not-allowed;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值