William
William

Reputation: 241

React Functional Component: How to prevent form from submitting if validation failed

I need some help, I am new to react. I created a Functional Component form with Context API and I am trying to prevent it from submitting if the form failed validation and return false. I have check the validation and it is working by uncommenting the html input button and comment out the React Link (<Link></Link>) button. I try the code with class component and bind the handleChange and handleSubmit inside the constructor and it work: however, I do not want to used the class component. I just want to used the function component.

const Employee = () => {
  const ctx = useContext(FormActualContext);

  const handleChange = (event) => {
    ctx.handleChange({
      event,
      type: 'employee',
    });
  };

  const validate = () => {
    const {
      firstName,
      lastName,
      email,
      dateOfBirth,
      phoneNum,
    } = ctx.formData.employee;
    const { employee } = ctx.formErrors;
    let {
      firstNameError,
      lastNameError,
      emailError,
      dateOfBirthError,
      phoneNumError,
    } = employee;

    firstNameError = !firstName ? 'First name can not be blank' : '';
    lastNameError = lastName === '' ? 'Last name can not be blank' : '';
    dateOfBirthError = !dateOfBirth ? 'Enter a valid date of birth' : '';
    if (!validateEmail(email)) {
      emailError =
        email === '' ? 'Enter a valid email' : `${email} is not valid email`;
    } else {
      emailError = '';
    }
    if (!validatePhoneNumber(phoneNum)) {
      phoneNumError =
        phoneNum === ''
          ? 'Enter a valid phone'
          : `${phoneNum} is not a valid phone number`;
    } else {
      phoneNumError = '';
    }

    if (
      firstNameError ||
      lastNameError ||
      emailError ||
      dateOfBirthError ||
      phoneNumError
    ) {
      ctx.setFormErrors({
        employee: {
          ...employee,
          firstNameError,
          lastNameError,
          emailError,
          dateOfBirthError,
          phoneNumError,
        },
      });
      return false;
    }
    return true;
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    const isValid = validate();
    if (isValid) {
      ctx.reSetEmployee();
    }
  };
  const {
    employee: {
      firstNameError,
      lastNameError,
      emailError,
      dateOfBirthError,
      phoneNumError,
    },
  } = ctx.formErrors;
  return (
    <div className="container_fluid">
      <div className="registration_form_container">
        <div className="register_context">
          <form action="" onSubmit={handleSubmit} className="registration_form">
            <div className="form-group">
              <input
                type="text"
                name="firstName"
                id="firstName"
                placeholder={'Enter first name'}
                onChange={handleChange}
              />
              <span>{firstNameError}</span>
            </div>
            <div className="form-group">
              <input
                type="text"
                name="lastName"
                id="lastName"
                placeholder={'Enter last name'}
                onChange={handleChange}
              />
              <span>{lastNameError}</span>
            </div>
            <div className="form-group">
              <input
                type="text"
                name="email"
                id="email"
                placeholder={'Enter email address'}
                onChange={handleChange}
              />
              <span>{emailError}</span>
            </div>
            <div className="form-group">
              <input
                type="date"
                name="dateOfBirth"
                id="dateOfBirth"
                placeholder={'Enter date of birth'}
                onChange={handleChange}
              />
              <span>{dateOfBirthError}</span>
            </div>
            <div className="form-group">
              <input
                type="text"
                name="phoneNum"
                id="phoneNum"
                placeholder={'Enter phone number (international: +1)'}
                onChange={handleChange}
              />
              <span>{phoneNumError}</span>
            </div>
            <div className="form-group custom_btn_container">
              {/*<input type="submit" className="btn" value="Register"/>*/}
              <Link to="/addressForm">
                <input type="submit" className="btn" value="Register" />
              </Link>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
};

Upvotes: 1

Views: 1006

Answers (1)

Drew Reese
Drew Reese

Reputation: 202696

Issue

The issue isn't that the form is being submitted upon validation (true or false), but rather that both field validation and route navigation are more or less occurring at the same time. The Link, upon being clicked, will immediately navigate to the specified path.

Solution

Seems you want to validate the input, and only upon successful validation, call the reSetEmployee function on the context and navigate to "/addressForm".

I suggest rendering the submit button not within a Link and use imperative navigation. For this I'm assuming you are using react-router-dom library.

import { useHistory } from 'react-router-dom';

...

const history = useHistory();

...

const handleSubmit = (event) => {
  event.preventDefault();
  const isValid = validate();
  if (isValid) {
    ctx.reSetEmployee();
    history.push("/addressForm");
  }
};

...

<div className="form-group custom_btn_container">
  <input type="submit" className="btn" value="Register"/>
</div>

Upvotes: 1

Related Questions