Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally render error in react js?

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 :)

like image 535
Sri Vineeth Avatar asked Mar 18 '21 10:03

Sri Vineeth


2 Answers

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.

like image 144
pouria Avatar answered Sep 27 '22 23:09

pouria


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

like image 40
Lakshya Thakur Avatar answered Sep 27 '22 23:09

Lakshya Thakur