Lab 16: Form Validation
Objectives
- Add Form Validation
Steps
Add Form Validation
- Open the file - src\project\ProjectForm.jsx
- Initialize an - errorsobject as a state variable to- {name: '', description: '', budget: ''}so we can hold form errors in the component's- state.- src\projects\ProjectForm.jsx- ...
 function ProjectForm({
 project: initialProject,
 onSave,
 onCancel,
 }) {
 const [project, setProject] = useState(initialProject);
 + const [errors, setErrors] = useState({
 + name: '',
 + description: '',
 + budget: '',
 + });
 ...
 }
 ...
 export default ProjectForm;
- Implement a - validatefunction in the- ProjectFormcomponent 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 - isValidfunction in the- ProjectFormcomponent that checks whether there are any validation errors.- src\projects\ProjectForm.jsx- ...
 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 - validatefunction inside- handleChangeto determine if there are any errors and then set them into the- errorsstate 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 - isValidfunction on form submit and return back out of the function before saving changes if the form is invalid.- src\projects\ProjectForm.jsx- ...
 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 - HTMLtemplate.- <div class="card error">
 <p>error message</p>
 </div>- src\projects\ProjectForm.jsx- ...
 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.