Home > Enterprise >  I want Link component from router dom to work only when validation is correct
I want Link component from router dom to work only when validation is correct

Time:11-15

I want if is possible the Link component from react-router-dom to not work until validations are made correct. If I remove the link, validation works as I want.

I saw something with ifValidate but I don't understand exactly how to apply it.

import { Link } from "react-router-dom";

const AgentProfile = () => {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [phone, setPhone] = useState("");
  const [proficiency, setProficiency] = useState("");
  const [address, setAddress] = useState("");
  const [city, setCity] = useState("");

  const [firstNameError, setFirstNameError] = useState(false);
  const [lastNameError, setLastNameError] = useState(false);
  const [phoneError, setPhoneError] = useState(false);
  const [proficiencyError, setProficiencyError] = useState(false);
  const [addressError, setAddressError] = useState(false);
  const [cityError, setCityError] = useState(false);

  const handleSubmit = (e) => {
    e.preventDefault();
    setFirstNameError(false);
    setLastNameError(false);
    setPhoneError(false);
    setProficiencyError(false);
    setAddressError(false);
    setCityError(false);

    if (firstName === "") {
      setFirstNameError(true);
    }

    if (lastName === "") {
      setLastNameError(true);
    }

    if (phone === "") {
      setPhoneError(true);
    }

    if (proficiency === "") {
      setProficiencyError(true);
    }

    if (address === "") {
      setAddressError(true);
    }

    if (city === "") {
      setCityError(true);
    }

    if (firstName && lastName && phone && proficiency && address && city) {
      console.log(firstName, lastName, phone, proficiency, address, city);
    }
  };

  return (
    <>
      <Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
        <Box ml={10} pt={6}>
          <Typography variant="h3" color="GrayText">
            Hello! Please tell us a little bit about yourself.
          </Typography>
        </Box>
        <form noValidate autoComplete="off" onSubmit={handleSubmit}>
          <Box sx={{ display: "flex" }} ml={10} mt={2}>
            <Box sx={{ width: "50%" }}>
              {/* <Typography variant="body2">First Name</Typography> */}
              <TextField
                onChange={(e) => setFirstName(e.target.value)}
                label="First Name"
                type="text"
                required
                variant="outlined"
                size="small"
                error={firstNameError}
              />
            </Box>
            <Box>
              {/* <Typography variant="body2">Last Name</Typography> */}
              <TextField
                onChange={(e) => setLastName(e.target.value)}
                label="Last Name"
                type="text"
                required
                variant="outlined"
                size="small"
                error={lastNameError}
              />
            </Box>
          </Box>
          <Box sx={{ display: "flex" }} ml={10} mt={4}>
            <Box sx={{ width: "50%" }}>
              {/* <Typography variant="body2">Phone</Typography> */}
              <TextField
                onChange={(e) => setPhone(e.target.value)}
                label="Phone"
                type="text"
                required
                variant="outlined"
                size="small"
                error={phoneError}
              />
            </Box>
            <Box sx={{ width: "30%" }}>
              {/* <Typography variant="body2">Work Proficiency</Typography> */}
              <FormControl fullWidth size="small" required>
                <InputLabel id="demo-simple-select-label">
                  Work Proficiency
                </InputLabel>
                <Select
                  onChange={(e) => setProficiency(e.target.value)}
                  labelId="demo-simple-select-label"
                  id="demo-simple-select"
                  value={proficiency}
                  label="Work Proficiency"
                  error={proficiencyError}
                >
                  <MenuItem value={2}>Two years</MenuItem>
                  <MenuItem value={5}>Five years</MenuItem>
                  <MenuItem value={10}>Ten years</MenuItem>
                </Select>
              </FormControl>
            </Box>
          </Box>
          <Box ml={10} mt={6}>
            {/* <Typography variant="body2">Street Address</Typography> */}
            <TextField
              onChange={(e) => setAddress(e.target.value)}
              label="Street Address"
              type="text"
              required
              variant="outlined"
              size="small"
              sx={{ width: "80%" }}
              error={addressError}
            />
          </Box>
          <Box ml={10} mt={6}>
            {/* <Typography variant="body2">City</Typography> */}
            <TextField
              onChange={(e) => setCity(e.target.value)}
              label="City"
              type="text"
              required
              variant="outlined"
              size="small"
              sx={{ width: "40%" }}
              error={cityError}
            />
          </Box>
          <Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
            <Box ml={8}>
              <Button variant="outlined" sx={{ borderRadius: "20px" }}>
                Back
              </Button>
            </Box>
            <Box mr={18}>
              <Button
                type="submit"
                variant="contained"
                sx={{ borderRadius: "20px" }}
              >
                <Link to="/experienceconfirm">Next</Link>
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </>
  );
};

export default AgentProfile;

Something like if validation is not correct link component to be disabled, and when user completes every field to become active.

CodePudding user response:

You can prevent the default link action when the link is clicked and add an imperative navigation action in the form's submit handler when validation is passed. Additionally you can disable the button while any state is still falsey.

Example:

import { Link, useNavigate } from 'react-router-dom';

const AgentProfile = () => {
  const navigate = useNavigate();

  ...

  const handleSubmit = (e) => {
    e.preventDefault();
    setFirstNameError(false);
    setLastNameError(false);
    setPhoneError(false);
    setProficiencyError(false);
    setAddressError(false);
    setCityError(false);

    let isError = false;

    if (!firstName) {
      setFirstNameError(true);
      isError = true;
    }

    if (!lastName) {
      setLastNameError(true);
      isError = true;
    }

    if (!phone) {
      setPhoneError(true);
      isError = true;
    }

    if (!proficiency) {
      setProficiencyError(true);
      isError = true;
    }

    if (!address) {
      setAddressError(true);
      isError = true;
    }

    if (!city) {
      setCityError(true);
      isError = true;
    }

    if (!isError) {
      navigate("/experienceconfirm"); // <-- navigate on no error
    }
  };

  return (
    <>
      <Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
        ...
        <form noValidate autoComplete="off" onSubmit={handleSubmit}>
          ...
          <Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
            <Box ml={8}>
              <Button variant="outlined" sx={{ borderRadius: "20px" }}>
                Back
              </Button>
            </Box>
            <Box mr={18}>
              <Button
                type="submit"
                variant="contained"
                sx={{ borderRadius: "20px" }}
                disabled={!(firstName && lastName && phone && proficiency && address && city)}
              >
                <Link
                  to="/experienceconfirm"
                  onClick={e => e.preventDefault()} // <-- prevent immediate navigation
                >
                  Next
                </Link>
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </>
  );
};

CodePudding user response:

import { useEffect, useMemo } from "react";
import { Link } from "react-router-dom";

const AgentProfile = () => {
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [phone, setPhone] = useState("");
  const [proficiency, setProficiency] = useState("");
  const [address, setAddress] = useState("");
  const [city, setCity] = useState("");

  const [firstNameError, setFirstNameError] = useState(false);
  const [lastNameError, setLastNameError] = useState(false);
  const [phoneError, setPhoneError] = useState(false);
  const [proficiencyError, setProficiencyError] = useState(false);
  const [addressError, setAddressError] = useState(false);
  const [cityError, setCityError] = useState(false);

  useEffect(() => {
    if (firstName === "") {
      setFirstNameError(true);
    }

    if (lastName === "") {
      setLastNameError(true);
    }

    if (phone === "") {
      setPhoneError(true);
    }

    if (proficiency === "") {
      setProficiencyError(true);
    }

    if (address === "") {
      setAddressError(true);
    }

    if (city === "") {
      setCityError(true);
    }
  }, [firstName, lastName, phone, proficiency, address, city])

  const hasError = useMemo(
    () => firstNameError || lastNameError || phoneError || proficiencyError || addressError || cityError
    , [firstNameError, lastNameError, phoneError, proficiencyError, addressError, cityError]
  )

  return (
    <>
      <Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
        <Box ml={10} pt={6}>
          <Typography variant="h3" color="GrayText">
            Hello! Please tell us a little bit about yourself.
          </Typography>
        </Box>
        <form noValidate autoComplete="off" onSubmit={handleSubmit}>
          <Box sx={{ display: "flex" }} ml={10} mt={2}>
            <Box sx={{ width: "50%" }}>
              {/* <Typography variant="body2">First Name</Typography> */}
              <TextField
                onChange={(e) => setFirstName(e.target.value)}
                label="First Name"
                type="text"
                required
                variant="outlined"
                size="small"
                error={firstNameError}
              />
            </Box>
            <Box>
              {/* <Typography variant="body2">Last Name</Typography> */}
              <TextField
                onChange={(e) => setLastName(e.target.value)}
                label="Last Name"
                type="text"
                required
                variant="outlined"
                size="small"
                error={lastNameError}
              />
            </Box>
          </Box>
          <Box sx={{ display: "flex" }} ml={10} mt={4}>
            <Box sx={{ width: "50%" }}>
              {/* <Typography variant="body2">Phone</Typography> */}
              <TextField
                onChange={(e) => setPhone(e.target.value)}
                label="Phone"
                type="text"
                required
                variant="outlined"
                size="small"
                error={phoneError}
              />
            </Box>
            <Box sx={{ width: "30%" }}>
              {/* <Typography variant="body2">Work Proficiency</Typography> */}
              <FormControl fullWidth size="small" required>
                <InputLabel id="demo-simple-select-label">
                  Work Proficiency
                </InputLabel>
                <Select
                  onChange={(e) => setProficiency(e.target.value)}
                  labelId="demo-simple-select-label"
                  id="demo-simple-select"
                  value={proficiency}
                  label="Work Proficiency"
                  error={proficiencyError}
                >
                  <MenuItem value={2}>Two years</MenuItem>
                  <MenuItem value={5}>Five years</MenuItem>
                  <MenuItem value={10}>Ten years</MenuItem>
                </Select>
              </FormControl>
            </Box>
          </Box>
          <Box ml={10} mt={6}>
            {/* <Typography variant="body2">Street Address</Typography> */}
            <TextField
              onChange={(e) => setAddress(e.target.value)}
              label="Street Address"
              type="text"
              required
              variant="outlined"
              size="small"
              sx={{ width: "80%" }}
              error={addressError}
            />
          </Box>
          <Box ml={10} mt={6}>
            {/* <Typography variant="body2">City</Typography> */}
            <TextField
              onChange={(e) => setCity(e.target.value)}
              label="City"
              type="text"
              required
              variant="outlined"
              size="small"
              sx={{ width: "40%" }}
              error={cityError}
            />
          </Box>
          <Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
            <Box ml={8}>
              <Button variant="outlined" sx={{ borderRadius: "20px" }}>
                Back
              </Button>
            </Box>
            <Box mr={18}>
              <Button
                type="submit"
                variant="contained"
                sx={{ borderRadius: "20px" }}
              >
                {hasError? "Next" : <Link to="/experienceconfirm">Next</Link>}
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </>
  );
};

export default AgentProfile;

I added useEffect to define whether the user inputted all fields or not. If there is an error, the button only shows the string and has no action.

  • Related