- Add Form Validation
-
Open the file
src\project\ProjectForm.js
-
Initialize an
errors
object as a state variable to{name: '', description: '', budget: ''}
so we can hold form errors in the component'sstate
.... function ProjectForm({ project: initialProject, onSave, onCancel, }) { const [project, setProject] = useState(initialProject); + const [errors, setErrors] = useState({ + name: '', + description: '', + budget: '', + }); ... } ... export default ProjectForm;
-
Implement a
validate
function in theProjectForm
component that meets these requirements.- Name is required.
- Name needs to be at least 3 characters long.
- Description is required.
- Budget must be greater than $0.
Also, implement an
isValid
function in theProjectForm
component that checks whether there are any validation errors.... function ProjectForm({ project: initialProject, onSave, onCancel, }) { const [project, setProject] = useState(initialProject); const [errors, setErrors] = useState({ name: '', description: '', budget: '', }); const handleChange = (event) => { ... }; + function validate(project) { + let errors = { name: '', description: '', budget: '' }; + if (project.name.length === 0) { + errors.name = 'Name is required'; + } + if (project.name.length > 0 && project.name.length < 3) { + errors.name = 'Name needs to be at least 3 characters.'; + } + if (project.description.length === 0) { + errors.description = 'Description is required.'; + } + if (project.budget === 0) { + errors.budget = 'Budget must be more than $0.'; + } + return errors; + } + function isValid() { + return ( + errors.name.length === 0 && + errors.description.length === 0 && + errors.budget.length === 0 + ); + } return ( ... ); } ... export default ProjectForm;
-
Call the
validate
function insidehandleChange
to determine if there are any errors and then set them into theerrors
state variable.... function ProjectForm({ project: initialProject, onSave, onCancel, }) { ... const handleChange = (event) => { const { type, name, value, checked } = event.target; // if input type is checkbox use checked // otherwise it's type is text, number etc. so use value let updatedValue = type === 'checkbox' ? checked : value; //if input type is number convert the updatedValue string to a number if (type === 'number') { updatedValue = Number(updatedValue); } const change = { [name]: updatedValue, }; let updatedProject; // need to do functional update b/c // the new project state is based on the previous project state // so we can keep the project properties that aren't being edited like project.id // the spread operator (...) is used to // spread the previous project properties and the new change setProject((p) => { updatedProject = new Project({ ...p, ...change }); return updatedProject; }); + setErrors(() => validate(updatedProject)); }; return ( ... ); } ... export default ProjectForm;
-
Call the
isValid
function on form submit and return back out of the function before saving changes if the form is invalid.... function ProjectForm({ project: initialProject, onSave, onCancel, }) { ... const handleSubmit = (event) => { event.preventDefault(); + if (!isValid()) return; onSave(project); }; ... return ( ... ); } ... export default ProjectForm;
-
In the JSX returned by the component: display the validation messages using the following
HTML
template.<div class="card error"> <p>error message</p> </div>
... function ProjectForm({ project: initialProject, onSave, onCancel, }) { const [project, setProject] = useState(initialProject); const [errors, setErrors] = useState({ name: '', description: '', budget: '', }); ... return ( <form className="input-group vertical" onSubmit={handleSubmit}> <label htmlFor="name">Project Name</label> <input type="text" name="name" placeholder="enter name" value={project.name} onChange={handleChange} /> + {errors.name.length > 0 && ( + <div className="card error"> + <p>{errors.name}</p> + </div> + )} <label htmlFor="description">Project Description</label> <textarea name="description" placeholder="enter description" value={project.description} onChange={handleChange} /> + {errors.description.length > 0 && ( + <div className="card error"> + <p>{errors.description}</p> + </div> + )} <label htmlFor="budget">Project Budget</label> <input type="number" name="budget" placeholder="enter budget" value={project.budget} onChange={handleChange} /> + {errors.budget.length > 0 && ( + <div className="card error"> + <p>{errors.budget}</p> + </div> + )} <label htmlFor="isActive">Active?</label> <input type="checkbox" name="isActive" checked={project.isActive} onChange={handleChange} /> <div className="input-group"> <button className="primary bordered medium">Save</button> <span /> <button type="button" className="bordered medium" onClick={onCancel}> cancel </button> </div> </form> ); } ... export default ProjectForm;
-
Verify the application is working by following these steps.
- Click the edit button on any project.
- Delete the contents of the project name textbox.
- Verify the error message displays.
- Test the other validation rules.