使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;
}