Search code examples
javascriptnode.jsreactjsreact-bootstrap

React Bootstrap can't validate forms


I am trying to add some validation to my React + Bootstrap project but I am not able to achieve this. According to Bootstrap Form validation documentation I have to provide a Form.Control.Feedback component to the Form Group component.

But is not showing the errors but check marks like everything is fine. I created this Code Sandbox yo demostrate what I need to achieve and what is showing me:

Edit magical-mcclintock-rnthy

And just in case, this is the code if you don't need the sandbox to see the error:

import React, { useState } from "react";
import "./styles.css";
import { Container, Form, Button } from "react-bootstrap";
import validator from "validator";
import empty from "is-empty";

export default function App() {
  const [validated, setValidated] = useState(false);
  const [errors, setErrors] = useState({});
  const [phone, setPhone] = useState("");
  const [email, setEmail] = useState("");

  const handleSubmit = async e => {
    e.preventDefault();

    const errors = {};

    // validation
    if (!validator.isMobilePhone(phone, ["es-UY"])) {
      errors.phone = "Invalid phone number";
    }

    if (!validator.isEmail(email)) {
      errors.email = "Invalid email address";
    }

    if (!empty(errors)) {
      setErrors(errors);
    }

    setValidated(true);
  };

  return (
    <Container>
      <Form validated={validated} onSubmit={handleSubmit}>
        <h1>Test form</h1>
        <Form.Group controlId="phone">
          <Form.Label>Phone number</Form.Label>
          <Form.Control
            type="tel"
            value={phone}
            onChange={e => setPhone(e.target.value)}
          />
          <Form.Control.Feedback type="invalid">Error</Form.Control.Feedback>
          {errors.phone && (
            <Form.Control.Feedback type="invalid">
              {errors.phone}
            </Form.Control.Feedback>
          )}
        </Form.Group>
        <Form.Group controlId="email">
          <Form.Label>Email address</Form.Label>
          <Form.Control
            type="email"
            value={email}
            onChange={e => setEmail(e.target.value)}
            feedback="Error"
          />
          {errors.email && (
            <Form.Control.Feedback type="invalid">
              {errors.email}
            </Form.Control.Feedback>
          )}
        </Form.Group>
        <Form.Group controld="submit">
          <Button type="submit" variant="primary">
            Submit
          </Button>
          <Button
            type="reset"
            variant="info"
            style={{ marginLeft: 10 }}
            onClick={() => {
              setErrors({});
              setValidated(false);
            }}
          >
            Reset
          </Button>
        </Form.Group>
      </Form>
    </Container>
  );
}

So, what am I doing wrong?


Solution

  • Make sure you've set setValidated as false for the errors

    const handleSubmit = async e => {
        e.preventDefault();
    
        const allErrors = {};  // <--- changed this as well
    
        // validation
        if (!validator.isMobilePhone(phone, ["es-UY"])) {
          allErrors.phone = "Invalid phone number";
        }
    
        if (!validator.isEmail(email)) {
          allErrors.email = "Invalid email address";
        }
    
        if (!empty(allErrors)) {
          setErrors(allErrors);
          setValidated(false);
        }
        else {
          setValidated(true);
        }
      };
    

    In your field add isInvalid as props:

    <Form.Control
       type="tel"
       value={phone}
       isInvalid={!!errors.phone}   <------
       onChange={e => setPhone(e.target.value)}
     />
    
      <Form.Control
        type="text"
        value={email}
        isInvalid={!!errors.email}  <-----
        onChange={e => setEmail(e.target.value)}
        feedback="Error"
       />