I am creating a form to update a patient object in the backend of my application. When I submit the form it gives me "TypeError: Cannot read properties of undefined (reading 'firstName')" and then shows this
72 | && <p className={styles.errMsg} name="errMsg" data-testid="errMsg">{constants.API_ERROR}</p>}
73 | {patient && (
74 | <form onSubmit={onSubmit}>
> 75 | <label htmlFor="firstName">
| ^ 76 | First Name:
77 | <input
78 | type="text"
Link to img of error if helpful
I've only ever gotten this error when an trying to read the properties of an object that hasn't been defined or isn't loading in time. I don't understand why this error is popping up here.
My code for the whole page if needed
/* eslint-disable react-hooks/exhaustive-deps */
import {
useState, React, useEffect, useContext
} from 'react';
import { useHistory } from 'react-router-dom';
import constants from '../../utils/constants';
import { UserContext } from '../context/UserContext';
import styles from './PatientsPage.module.css';
import { createNewPatient } from './PatientsService';
import patientValidator from './PatientValidator';
const EditPatientPage= () => {
const history = useHistory();
const { loggedIn } = useContext(UserContext);
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
age: '',
insuranceProvider: '',
email: '',
height: '',
weight: '',
ssn: '',
street1: '',
street2: '',
city: '',
state: '',
postal: '',
gender: ''
});
const [errors, setErrors] = useState({
firstName: '',
roomTypeId: '',
lastName: '',
numberOfNights: ''
});
const [apiError, setApiError] = useState(false);
const usStates = ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', 'VI', 'WA', 'WV', 'WI', 'WY'];
const genderOptions = ['Female', 'Male', 'Other'];
const onChangeForInputs = (e) => {
setFormData({ ...formData, [e.target.id]: e.target.value });
};
const onSubmit = async (e) => {
e.preventDefault();
setErrors(patientValidator(formData, setApiError));
if (sessionStorage.getItem('isValid')) { await createNewPatient(formData).then(() => history.push('/patients')); }
};
useEffect(async () => {
if (!loggedIn) {
history.push('/');
}
}, []);
return (
<div className="inputContainer">
{apiError
&& <p className={styles.errMsg} name="errMsg" data-testid="errMsg">{constants.API_ERROR}</p>}
<form onSubmit={onSubmit}>
<label htmlFor="firstName">
First Name:
<input type="text" id="firstName" name="firstName" className="input" onChange={onChangeForInputs} value={formData.firstName} />
</label>
{errors.firstName && (
<>
<span className={styles.error}>{errors.firstName}</span>
</>
)}
<br />
<label htmlFor="lastName">
Last Name:
<input type="text" id="lastName" name="lastName" className="input" onChange={onChangeForInputs} value={formData.lastName} />
</label>
{errors.lastName && (
<>
<span className={styles.error}>{errors.lastName}</span>
</>
)}
<br />
<label htmlFor="gender">
Gender:
<select name="gender" id="gender" className="input" onChange={onChangeForInputs} value={formData.gender}>
<option value="" onChange={onChangeForInputs} />
{genderOptions.map((gender) => (
<option value={gender} onChange={onChangeForInputs}>{gender}</option>
))}
</select>
</label>
{errors.state && (
<>
<span className={styles.error}>{errors.state}</span>
</>
)}
<br />
<label htmlFor="age">
Age:
<input type="number" id="age" name="age" className="input" onChange={onChangeForInputs} value={formData.age} />
</label>
{errors.age && (
<>
<span className={styles.error}>{errors.age}</span>
</>
)}
<br />
<label htmlFor="height">
Height:
<input type="number" id="height" name="height" className="input" onChange={onChangeForInputs} value={formData.height} />
</label>
{errors.height && (
<>
<span className={styles.error}>{errors.height}</span>
</>
)}
<br />
<label htmlFor="weight">
Weight:
<input type="number" id="weight" name="weight" className="input" onChange={onChangeForInputs} value={formData.weight} />
</label>
{errors.weight && (
<>
<span className={styles.error}>{errors.weight}</span>
</>
)}
<br />
<label htmlFor="ssn">
Social Security Number:
<input type="text" id="ssn" name="ssn" className="input" onChange={onChangeForInputs} value={formData.ssn} />
</label>
{errors.ssn && (
<>
<span className={styles.error}>{errors.ssn}</span>
</>
)}
<br />
<label htmlFor="street1">
Street:
<input type="text" id="street1" name="street1" className="input" onChange={onChangeForInputs} value={formData.street1} />
</label>
{errors.street1 && (
<>
<span className={styles.error}>{errors.street1}</span>
</>
)}
<br />
<label htmlFor="street2">
Apartment/Unit # (if Patient has one):
<input type="text" id="street2" name="street2" className="input" onChange={onChangeForInputs} value={formData.street2} />
</label>
{errors.street2 && (
<>
<span className={styles.error}>{errors.street2}</span>
</>
)}
<br />
<label htmlFor="city">
City:
<input type="text" id="city" name="city" className="input" onChange={onChangeForInputs} value={formData.city} />
</label>
{errors.city && (
<>
<span className={styles.error}>{errors.city}</span>
</>
)}
<br />
<label htmlFor="state">
State:
<select name="state" id="state" className="input" onChange={onChangeForInputs} value={formData.state}>
<option value="" onChange={onChangeForInputs} />
{usStates.map((state) => (
<option value={state} onChange={onChangeForInputs}>{state}</option>
))}
</select>
</label>
{errors.state && (
<>
<span className={styles.error}>{errors.state}</span>
</>
)}
<br />
<label htmlFor="postal">
Postal Code (Zip Code):
<input type="text" id="postal" name="postal" className="input" onChange={onChangeForInputs} value={formData.postal} />
</label>
{errors.postal && (
<>
<span className={styles.error}>{errors.postal}</span>
</>
)}
<br />
<label htmlFor="insuranceProvider">
Insurance Provider:
<input type="text" id="insuranceProvider" name="insuranceProvider" className="input" onChange={onChangeForInputs} value={formData.insuranceProvider} />
</label>
{errors.insuranceProvider && (
<>
<span className={styles.error}>{errors.insuranceProvider}</span>
</>
)}
<br />
<button type="submit" className="button">Edit Patient</button>
</form>
</div>
);
};
export default EditPatientPage;
code for the service methods
export const updatePatient = async (patient, setApiError) => {
await HttpHelper(`/patients/${patient.id}`, 'PUT', patient)
.then((response) => {
if (response.status !== 201) {
throw new Error(constants.API_ERROR);
}
return response.json();
})
.catch(() => {
setApiError(true);
});
};
export const getPatientById = async (
patientID, setPatient, setFormData, setApiError
) => {
await HttpHelper(`/patients/${patientID}`, 'GET')
.then((response) => {
if (response.status === 200) {
return response.json();
}
throw new Error(constants.API_ERROR);
})
.then((body) => {
setPatient(body);
setFormData({
firstName: body.firstName,
lastName: body.lastName,
age: body.age,
insuranceProvider: body.insuranceProvider,
email: body.email,
height: body.height,
weight: body.weight,
ssn: body.ssn,
street1: body.street1,
street2: body.street2,
city: body.city,
state: body.state,
postal: body.postal,
gender: body.gender
});
})
.catch(() => {
setApiError(true);
});
};
CodePudding user response:
Even so it's not a full answer: I think the error occurrs on the line below the shown (the one with the <input />
). But I cannot tell why formData
is undefined
in this moment.
CodePudding user response:
I figured it out the error was in the validator that I didn't provide in the original post.
I forgot to return the errors after validating so if anyone has a similar error in the future check to make sure you return values properly in your helper methods.
Here is the validator and its fixed version
const patientValidator = (patient) => {
const postalPattern = /^\d{5}$|^\d{5}-\d{4}$/;
const ssnPattern = /[0-9]{3}-[0-9]{2}-[0-9]{4}/;
const namePattern = /^[a-zA-z.'-]{2,}$/;
const emailPattern = /^[a-zA-z0-9] @[a-zA-Z] \.[a-zA-Z] $/;
sessionStorage.setItem('isValid', true);
const errors = {
firstName: '',
lastName: '',
age: '',
insuranceProvider: '',
email: '',
height: '',
weight: '',
ssn: '',
street1: '',
street2: '',
city: '',
state: '',
postal: '',
gender: ''
};
if (patient.firstName === '') {
errors.fName = 'The First Name field is required and can take all alphabetical characters and the following special characters .\'-';
sessionStorage.setItem('isValid', false);
} else if (!namePattern.test(patient.firstName)) {
errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
sessionStorage.setItem('isValid', false);
}
if (patient.lastName === '') {
errors.fName = 'The Last Name field is required and can take all alphabetical characters and the following special characters .\'-';
sessionStorage.setItem('isValid', false);
} else if (!namePattern.test(patient.lastName)) {
errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
sessionStorage.setItem('isValid', false);
}
if (patient.postal === '') {
errors.postal = 'The Postal Code field is required and can take either postal code format (E.G. 12345 or 12345-6789)';
sessionStorage.setItem('isValid', false);
} else if (!postalPattern.test(patient.postal)) {
errors.postal = 'Input invalid the only characters allowed are numbers and a single hyphen in the following format (E.G. 12345 or 12345-6789)';
sessionStorage.setItem('isValid', false);
}
if (patient.email === '') {
errors.email = 'The Email field is required and can take email addresses in the following format (E.G. [email protected])';
sessionStorage.setItem('isValid', false);
} else if (!emailPattern.test(patient.email)) {
errors.email = 'Invalid input please ensure the email input is in the following format (E.G. [email protected])';
sessionStorage.setItem('isValid', false);
}
if (patient.age === '') {
errors.age = 'The Age field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
} else if (!(/\d /.test(patient.age))) {
errors.age = 'The age field can only take whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.street1 === '') {
errors.street1 = 'The Street field is required';
sessionStorage.setItem('isValid', false);
}
if (patient.city === '') {
errors.city = 'The City field is required and can only take in aphabetical characters';
sessionStorage.setItem('isValid', false);
}
if (patient.state === '') {
errors.state = 'The State field is required please select one from the dropdown';
}
if (patient.height === '') {
errors.height = 'The Height field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.weight === '') {
errors.weight = 'The Weight field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.ssn === '') {
errors.ssn = 'The Social Security Number field is required and should follow the format 123-45-6789';
sessionStorage.setItem('isValid', false);
} else if (!ssnPattern.test(patient.ssn)) {
errors.ssn = 'Invalid input please ensure ssn input is in the following format 123-45-6789';
}
if (patient.insuranceProvider === '') {
errors.insuranceProvider = 'The Insurance Provider field is required if the patient Uninsured or Self Insured enter that instead of leaving the field blank';
sessionStorage.setItem('isValid', false);
}
if (patient.gender === '') {
errors.gender = 'The Gender field is required please select the one that best represents the patient from the dropdown';
sessionStorage.setItem('isValid', false);
}
}; export default patientValidator;
const patientValidator = (patient) => {
const postalPattern = /^\d{5}$|^\d{5}-\d{4}$/;
const ssnPattern = /[0-9]{3}-[0-9]{2}-[0-9]{4}/;
const namePattern = /^[a-zA-z.'-]{2,}$/;
const emailPattern = /^[a-zA-z0-9] @[a-zA-Z] \.[a-zA-Z] $/;
sessionStorage.setItem('isValid', true);
const errors = {
firstName: '',
lastName: '',
age: '',
insuranceProvider: '',
email: '',
height: '',
weight: '',
ssn: '',
street1: '',
street2: '',
city: '',
state: '',
postal: '',
gender: ''
};
if (patient.firstName === '') {
errors.fName = 'The First Name field is required and can take all alphabetical characters and the following special characters .\'-';
sessionStorage.setItem('isValid', false);
} else if (!namePattern.test(patient.firstName)) {
errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
sessionStorage.setItem('isValid', false);
}
if (patient.lastName === '') {
errors.fName = 'The Last Name field is required and can take all alphabetical characters and the following special characters .\'-';
sessionStorage.setItem('isValid', false);
} else if (!namePattern.test(patient.lastName)) {
errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
sessionStorage.setItem('isValid', false);
}
if (patient.postal === '') {
errors.postal = 'The Postal Code field is required and can take either postal code format (E.G. 12345 or 12345-6789)';
sessionStorage.setItem('isValid', false);
} else if (!postalPattern.test(patient.postal)) {
errors.postal = 'Input invalid the only characters allowed are numbers and a single hyphen in the following format (E.G. 12345 or 12345-6789)';
sessionStorage.setItem('isValid', false);
}
if (patient.email === '') {
errors.email = 'The Email field is required and can take email addresses in the following format (E.G. [email protected])';
sessionStorage.setItem('isValid', false);
} else if (!emailPattern.test(patient.email)) {
errors.email = 'Invalid input please ensure the email input is in the following format (E.G. [email protected])';
sessionStorage.setItem('isValid', false);
}
if (patient.age === '') {
errors.age = 'The Age field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
} else if (!(/\d /.test(patient.age))) {
errors.age = 'The age field can only take whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.street1 === '') {
errors.street1 = 'The Street field is required';
sessionStorage.setItem('isValid', false);
}
if (patient.city === '') {
errors.city = 'The City field is required and can only take in aphabetical characters';
sessionStorage.setItem('isValid', false);
}
if (patient.state === '') {
errors.state = 'The State field is required please select one from the dropdown';
}
if (patient.height === '') {
errors.height = 'The Height field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.weight === '') {
errors.weight = 'The Weight field is required and can only take in whole numbers';
sessionStorage.setItem('isValid', false);
}
if (patient.ssn === '') {
errors.ssn = 'The Social Security Number field is required and should follow the format 123-45-6789';
sessionStorage.setItem('isValid', false);
} else if (!ssnPattern.test(patient.ssn)) {
errors.ssn = 'Invalid input please ensure ssn input is in the following format 123-45-6789';
}
if (patient.insuranceProvider === '') {
errors.insuranceProvider = 'The Insurance Provider field is required if the patient Uninsured or Self Insured enter that instead of leaving the field blank';
sessionStorage.setItem('isValid', false);
}
if (patient.gender === '') {
errors.gender = 'The Gender field is required please select the one that best represents the patient from the dropdown';
sessionStorage.setItem('isValid', false);
}
return errors;
}; export default patientValidator;
as you can see my validator simply lacked a return statement. Thanks to Gregor for pointing me to that fact that the error the browser was showing wasn't for the line it said it was on which led to me checking the error spans.