React : How can I set the error messages?

Viewed 46

I am trying to set the error message but as in the state I've passed initial Values object, I'm unable to set the state. How can I achieve this in react? How can I set the error messages in the set State function? Can someone help me?. After console logging it is showing the error in the console. But how can I show this on screen? Thanks in advance.

Here's the code :

const initialValues={
    deliverable_name:"",
    due_date:new Date(),
    deliverable_notes:"",
    milestone_based_payment:false,
    deliverable_name_error:"",
    due_date_error:"",
    deliverable_notes_error:""
}

class MileStoneForm extends Component {
    constructor(props){
        super(props)
        this.state={
            initialValues
        }
    }
    handleChange=(e,type)=>{
        let error=true
        if(type==='deliverable_notes'){
            if(e.target.value.length>300){
                error=false
                this.setState({deliverable_notes_error:'Description must contain less than 300 characters'})
            }
        }
        if(error){
            this.setState({
                [type]:e.target.value,
                [type+"_error"]: ""
            })
        }
    }

    validateMileStoneName=()=>{
        if(!this.state.initialValues.deliverable_name || this.state.initialValues.deliverable_name.length< 4 ){
            console.log("enter deliverable name")
            this.setState({deliverable_name_error:'Please enter deliverable name'})
        }
    }

    validateMileStoneDueDate=()=>{
        if(!this.state.initialValues.due_date){
            this.setState({due_date_error:'Please enter due date'})
        }
    }

    validateMileStoneDescription=()=>{
        if(!this.state.initialValues.deliverable_notes){
            this.setState({deliverable_notes_error:'Please enter description'})
        }
    }


    handleSubmit=(data)=>{
        this.validateMileStoneName()
        this.validateMileStoneDescription()
        console.log(data)
        this.props.handleData(data)
    }
   
    render() {
        const {initialValues}=this.state 
        return (
            <>
                <div className="milestone">
                    <div className="milestone-header">ADD MILESTONE</div>
                    <Grid container className="milestone-deliverable-name-date">
                        <Grid item md={6} lg={6} xs={12}>
                            <div className="milestone-deliverable-name">DELIVERABLE NAME</div>
                                <div>
                                    <InputBase
                                    className={`milestone-input-deliverable-name`}
                                    autoComplete={"off"}
                                    placeholder={"MileStone Name"}
                                    onChange={e=>this.handleChange(e,'initialValues.deliverable_name')}
                                    value={initialValues.deliverable_name}
                                    maxLength="100"
                                    autoFocus={true}/>
                                    {initialValues.deliverable_name_error && (
                                        <div className="input-error-style">{initialValues.deliverable_name_error}</div>
                                    )}
                                </div>
                        </Grid>
                        <Grid item md={6} lg={6} xs={12}>
                                <div>
                                    <div className="milestone-due-date">
                                        DUE DATE
                                    </div>
                                    <InputBase
                                        className={`create-project-due-date`}
                                        autoComplete={"off"}
                                        type="date"
                                        placeholder={"DUE DATE"}
                                        onChange={e=>this.handleChange(e,'due_date')}
                                        value={initialValues.due_date}/>
                                    {initialValues.due_date_error && (
                                        <div className="input-error-style">{initialValues.due_date_error}</div>
                                    )}
                                </div>
                        </Grid>
                    </Grid>
                    <Grid container className="milestone-deliverable-notes">
                        <Grid item md={12} lg={12} xs={12}>
                            <div className="milestone-notes-description">
                                <div className="milestone-deliverable-notes">DELIVERABLE NOTES</div>
                                <div className="milestone-description-notes">Add description below</div>
                                <TextareaAutosize className={`milestone-textarea-description`}
                                onChange={(e)=>this.handleChange(e,'deliverable_notes')}
                                value={initialValues.deliverable_notes}/>
                                {initialValues.deliverable_notes_error && (
                                    <div className="input-error-style">{initialValues.deliverable_notes_error}</div>
                                )}
                            </div>
                        </Grid>
                    </Grid>
                    <div className={initialValues.milestone_based_payment?"milestone-button":"milestone-button-margin-high"}>
                        <Grid container spacing={10}>
                            <Grid item xs={12} sm={12} md={4} lg={4}></Grid>
                            <Grid item xs={12} sm={12} md={4} lg={4}></Grid>
                            <Grid item xs={12} sm={12} md={4} lg={4}>
                                <div className="milestone-button-margin-btm">
                                <NormalButton
                                buttonValue="ADD"
                                className="btn-create-project flex-justify"
                                icon_color="black"
                                handleButtonAction={()=>this.handleSubmit(initialValues)}  
                                />
                                </div>
                            </Grid>
                        </Grid>
                    </div>
                </div> 
            </>
        )
    }
}

export default MileStoneForm
2 Answers

3 things

  1. I would move the error messages inside State.

    deliverable_name_error:"",
    due_date_error:"",
    deliverable_notes_error:""
    
  2. Update this.setState - already done

  3. Display error messages - also doing.

Basically, if you move everything from initialValues into state, your code should work.

You're mixing initialValue in the state which is an object, with the properties you're setting. So after an error, your state is actually looking like this:

this.state = {
  initialValue: [object] // this could potentially mutate (a bug).
  deliverable_notes_error: "Please set ....",
}

What you need to do is use the spread syntax to set your initial state:

constructor(props) {
  this.state = {
    ...initialValues // your state is now a soft clone of the object
  };
}

render(props) {
  const { deliverable_notes_error } = this.state;

  return (
    { deliverable_notes_error && <div>{ deliverable_notes_error }</div> }
  );
}
Related