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.