I have a register form component in reactjs with a material UI component. I have an array of objects that contains the value of props for the TextField component. If the field value is empty, I want to conditionally show the "Cannot be empty" helper text. E.g., if the email is not entered, but the name is entered, I should show the only Email that cannot be empty error text.
Errors I am facing: I am able to show the error, but even if one input is empty, an error is displayed in all fields.
Expected: Only corresponding TextField's helper text should be displayed if there were any error
I have tried - CodeSandBox link https://codesandbox.io/s/infallible-joliot-6vkrq?file=/src/App.jsfile=/src/App.js
In what way can I improve this? Any help is appreciated. Thanks :)
It's because you're using a boolean
. You should use an object instead:
import { Grid, TextField } from "@material-ui/core";
import { useState } from "react";
import "./styles.css";
export default function App() {
const [inputErrors, setInputErrors] = useState({}); // PLURALIZED AND INITIALIZED WITH AN EMPTY OBJECT
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleChange = (event, index, setValue, setError) => {
let value = event.target.value;
if (!value) {
setError(state => ({
...state,
[event.target.name]: true
}));
} else {
setError(state => ({
...state,
[event.target.name]: false
}));
setValue(value);
}
};
const arrObj = [
{
name: "Name",
input: "Please enter your name",
onChange: (event, index) =>
handleChange(event, index, setName, setInputErrors),
helperText: inputErrors.name && "*Name is Required"
},
{
name: "Email",
input: "enter your email address",
onChange: (event, index) =>
handleChange(event, index, setEmail, setInputErrors),
helperText: inputErrors.email && "*Email is Required"
}
];
return (
<div className="App">
{arrObj.map((item, index) => {
let { onChange, input, helperText } = item;
return (
<Grid key={index} item xs={12} style={{ textAlign: "center" }}>
<TextField
name={item.name.toLowerCase()}
placeholder={input}
required
onChange={(event) => onChange(event, index)}
helperText={helperText}
/>
</Grid>
);
})}
</div>
);
}
Here we assign a "name" attribute on the input fields and use it in the code as the key for the error.
You're using a single Boolean state inputError
to decide errors for both the name
and email
field so that's why you see the error. There is no way to distinguish from which field the error occured.
Instead of that you can have a dedicated inputError
object which acts as a Hashmap/Dictionary
for your input fields with true/false
indicating whether a particular field has error.
Whole code for reference :-
import { Grid, TextField } from "@material-ui/core";
import { useState } from "react";
import "./styles.css";
export default function App() {
const [inputError, setInputError] = useState({ name: false, email: false });
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleChange = (event, index, setValue, setError) => {
let { value, name } = event.target;
name = name.toLowerCase();
if (!value) setError({ ...inputError, [name]: true });
else {
setError({ ...inputError, [name]: false });
setValue(value);
}
};
const arrObj = [
{
name: "Name",
input: "Please enter your name",
onChange: (event, index) =>
handleChange(event, index, setName, setInputError),
helperText: inputError.name && "*Name is Required"
},
{
name: "Email",
input: "enter your email address",
onChange: (event, index) =>
handleChange(event, index, setEmail, setInputError),
helperText: inputError.email && "*Email is Required"
}
];
return (
<div className="App">
{arrObj.map((item, index) => {
let { onChange, input, helperText, name } = item;
return (
<Grid key={index} item xs={12} style={{ textAlign: "center" }}>
<TextField
name={name}
placeholder={input}
required
onChange={(event) => onChange(event, index)}
helperText={helperText}
/>
</Grid>
);
})}
</div>
);
}
Codesandbox Link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With