I want to use onBlur here but I'm making some mistake - reactjs

Here I want to use onBlur function here but the way I want is whenever I enter the email it should activate onBlur and whenever it is empty the input field should hide it but I'm not getting exact solution for this. Here is the code that I have used..
const [user, update_user] = useState({
user_name: "",
email: "",
clearUser: false,
clearEmail: false,
});
const clearValue = (key, show) => {
update_user({ ...user, [key]: "", [show]: false });
};
const [showSecondInput, setShowSecondInput] = useState(false);
const handleOTP = (e) => {
const { name:key, value } = e.target;
if(key=== "email") setShowSecondInput({ ...showSecondInput, [key]: "", clearEmail: true })
else
setShowSecondInput({...showSecondInput,[key]:"", clearEmail:false});
};
Here is the return/ main code
<Input
fullWidth
name="email"
value={user.email}
onChange={handleChange}
disableUnderline={true}
onBlur={handleOTP}
className={classes.inputEmail}
endAdornment={
<>
{user.clearEmail ? (
<IconButton
onClick={() => clearValue("email", "clearEmail")}
>
<ClearIcon />
</IconButton>
) : (
""
)}
</>
}
/>
{showSecondInput && (
<>
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
sx={{ mt: "5px" }}
>
Enter OTP
</Typography>
<Input
className={classes.inputEmail}
fullWidth
type="password"
/>
</>
)}

Related

This onBlur is not working the way I want

Here I want this onBlur to show another text or input field which is working but whenever i clear the value it should be hiding but right now it is not working the way I want. In easy words whenever I enter content in input field and loose the focus it show sub input field but whenever clear it all it should be hiding but it is not working here is the code
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
>
Email
</Typography>
<Input
fullWidth
name="email"
value={user.email}
onChange={handleChange}
disableUnderline={true}
onBlur={handleOTP}
className={classes.inputEmail}
endAdornment={
<>
{user.clearEmail ? (
<IconButton
onClick={() => clearValue("email", "clearEmail")}
>
<ClearIcon />
</IconButton>
) : (
""
)}
</>
}
/>
{showSecondInput && (
<>
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
sx={{ mt: "15px" }}
>
Enter OTP
</Typography>
<Input
className={classes.inputEmail}
fullWidth
type="password"
/>
</>
)}
This is the states I have used
const [user, update_user] = useState({
user_name: "",
email: "",
clearUser: false,
clearEmail: false,
});
const clearValue = (key, show) => {
update_user({ ...user, [key]: "", [show]: false });
};
const [showSecondInput, setShowSecondInput] = useState(false);
const handleOTP = (e) => {
const { name:key } = e.target;
if(key === "email") setShowSecondInput({ ...showSecondInput, [key]: "", clearEmail: false });
};
const handleChange = (event) => {
const { name: key, value } = event.target;
if (value) {
if (key === "user_name")
update_user({ ...user, [key]: value, clearUser: true });
else if (key === "email")
update_user({
...user,
[key]: value,
clearEmail: true,
});
} else
update_user({
...user,
[key]: "",
clearUser: false,
clearEmail: false,
});
};
The clearValue function is working smoothly without any problem the problem is on blur event..
You could do this by checking for the name in case you have more onBlur with the handleOTP function. Then checking if the value is a empty string and based on that set the state.
const handleOTP = (e) => {
const { name, value } = e.target;
if (name !== "email") return;
if (value === "") {
setShowSecondInput(true);
} else {
setShowSecondInput(false);
}
};

Formik/Yup validation for different views in one form (React, MUI, Firebase)

I am creating an interactive React app. I want it to be as optimal and modular as possible, so I created ONE authentication form, and I switch the various sub-forms (SignIn, SignUp, ForgotPassword) in the App component.
How do I define different validation schemas (yup), and initial values for each separate form, while nested in one physical Form component?
This is what my form looks like right now:
(Authentication.jsx)
const Authentication = ({ title }) => {
return (
<Container id='auth'>
<center>
<Formik
initialValues={{ name: '' }}
validationSchema={validationSchema}
onSubmit={(values, actions) => {
setTimeout(() => {
actions.setSubmitting(false);
}, 1000);
}}>
{(props) => (
/* Authentication Form */
<Form autoComplete='off' className='auth-form' noValidate>
<h2 className='auth-title'>{title}</h2>
{title === 'Sign In' ? (
<SignIn />
) : title === 'Sign Up' ? (
<SignUp />
) : (
<ForgotPassword />
)}
</Form>
)}
</Formik>
</center>
</Container>
);
};
and an example sub-form:
(SignIn.jsx)
const validationSchema = yup.object().shape({
email: yup.string().email('Invalid email').required('Required'),
password: yup.string().password('Invalid password').required('Required'),
});
const SignIn = ({ name, errors, touched, ...props }) => {
const { values, submitForm } = useFormikContext();
const [input, setInputs] = useState({
email: '',
password: '',
});
const handleSetValues = (name) => (e) => {
let formikValue = 'formik.values.' + name;
setInputs({
...input,
[name]: e.target.value,
[formikValue]: e.target.value,
});
};
const [signInWithEmailAndPassword, user, loading, error] = useSignInWithEmailAndPassword(auth);
const [showPassword, setShow] = useState(false);
const navigate = useNavigate();
useEffect(() => {
if (loading || error) {
return;
}
if (user) {
navigate('/workshop');
}
}, [user, loading, error]);
const handleSubmit = (e) => {
e.preventDefault();
if (submitForm) {
signInWithEmailAndPassword(input.email, input.password).catch((err) => {
console.log(err);
});
}
};
return (
<div id='login'>
<Row>
{/* Email Input */}
<TextField
id='email'
label='Email'
variant='standard'
required
type='email'
value={input.email}
onChange={(e) => handleSetValues('email')}
error={values.touched.email && Boolean(values.errors.email)}
helperText={values.touched.email && values.errors.email}
/>
</Row>
<Row>
{/* Password Input */}
<FormControl variant='standard'>
<InputLabel htmlFor='password'>Password</InputLabel>
<Input
id='password'
label='Password'
variant='standard'
required
type={showPassword ? 'text' : 'password'}
value={input.password}
onChange={(e) => handleSetValues('password')}
error={values.touched.password && Boolean(values.errors.password)}
helperText={values.touched.password && values.errors.password}
// {...(error && { error: true, helperText: getError(error) })}
endAdornment={
<InputAdornment position='end'>
<IconButton
aria-label='toggle password visibility'
onClick={() => setShow(!showPassword)}
onMouseDown={(e) => e.preventDefault}
edge='end'>
{showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
/>
</FormControl>
</Row>
{/* Display Error */}
<div className='error'>{error ? getError(error) : ' '}</div>
{/* Submit Button */}
<Button className='btn-auth' type='submit' onClick={handleSubmit}>
Sign In
</Button>
<Row>
{/* Link to Register */}
<Link link='/register' pretext='New to AME?' text='Sign Up' posttext='now.' />
{/* Link to Reset Password */}
<Link link='/forgot' text='Forgot password?' />
</Row>
</div>
);
};

React formik Validation Error Api Renders Every Time when other field validate

I've created a register form I tried to validate the form onBlur and the one has an email check with backend Apis, I have an issue when I validate any other that case mail check API render every time
I tried with onBlur and onChange validation false that case working fine, But I need onBlur validation, Any Ideas
Thanks for Help
const CompanyRegister = (props) => {
const classes = useStyles();
var [mailError, setMailError] = useState(false);
const initialValues = {
name: "",
website: "",
addressLine1: "",
city: "",
state: "",
mail: "",
};
const validationSchema = yup.object({
name: yup.string().strict().trim().required("Enter the ComapnyName"),
website: yup
.string()
.matches(
/((https?):\/\/)?(www.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/,
"Enter correct url!"
)
.strict()
.trim()
.required("Enter the Website"),
pincode: yup.number("Invalid pincode").positive("Invalid pincode"),
phone: yup.number("InValid Phone Number"),
altPhone: yup.number("InValid Phone Number"),
mail: yup
.string()
.email("Enter correct Format")
.strict()
.trim()
.required("Enter the Correct Email"),
});
const validCheck = (data) => {
var mailData = { mail: data };
axios.post(baseurl + "companymailcheck", mailData).then((res) => {
if (res.data == "Invalid") {
setMailError(true);
} else {
setMailError(false);
}
});
};
const onSubmit = (data) => {
axios
.post(baseurl + "companyregisteration", data)
.then((res) => {
history.push(`/login`);
toast.success("Successfully Created");
})
.catch((err) => {
toast.error("Some Thing Error");
});
};
return (
<>
<div className={classes.back}>
<Link to="/">Home</Link>
</div>
<Container component="main" className={classes.layout}>
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Register
</Typography>
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validateOnChange={false}
validateOnBlur={true}
validationSchema={validationSchema}
>
{({ values, isValid }) => {
return (
<Form autoComplete="off">
<Grid container spacing={4}>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="name"
fullWidth
label="Company Name"
autoFocus
required
/>
<ErrorMessage name="name">
{(error) => (
<div className={classes.error}>{error}</div>
)}
</ErrorMessage>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="website"
fullWidth
label="Website"
required
/>
<ErrorMessage name="website">
{(error) => (
<div className={classes.error}>{error}</div>
)}
</ErrorMessage>
</Grid>
<Grid item xs={12} sm={12}>
<Field
as={TextField}
name="addressLine1"
type="text"
fullWidth
label="Address Line1"
/>
</Grid>
<Grid item xs={12} sm={6}>
<Field
as={TextField}
name="mail"
fullWidth
label="Mail"
required
validate={() => validCheck(values.mail)}
/>
<ErrorMessage name="mail">
{(error) => (
<div className={classes.error}>{error}</div>
)}
</ErrorMessage>
{mailError ? (
<span style={{ color: "red" }} id="errormessage">
Mail Already There!
</span>
) : null}
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
disabled={!isValid || mailError}
>
Register
</Button>
</Grid>
</Form>
);
}}
</Formik>
</div>
</Container>
</>
);
};
export default CompanyRegister;
As long as it's fine to perform the validation during form submission then I would extend the onSubmit and put the check there.
You can use the second parameter which will return the FormikBag containing all relevant setter's to invalidate the form-field properly. Reference: https://formik.org/docs/api/formik#onsubmit-values-values-formikbag-formikbag--void--promiseany
In this case I would use setFieldError(field, message). Reference: https://formik.org/docs/api/formik#setfielderror-field-string-errormsg-string--void
<Formik initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(values, {setFieldError}) => {
return validateMail(values.mail)
.then(() => {
// all good - continue with your submit handler
return onSubmit(values)
})
.catch(error => {
// something wrong? validate the error response + validation message OR set it statically.
setFieldError('mail', 'Mail Already There!')
})
}}
>

Unable to reset value in State of React

export default function Register() {
const [formData, setformData] = useState({
name: "",
emailid: "",
password: "",
password2: "",
});
const [formHelperText, setFormHelperText] = useState({
formHelperTextname: "",
formHelperTextemailid: "",
formHelperTextpassword: "",
formHelperTextpassword2: "",
});
const { name, emailid, password, password2 } = formData;
const {
formHelperTextname,
formHelperTextemailid,
formHelperTextpassword,
formHelperTextpassword2,
} = formHelperText;
const onChange = (e) => {
setformData({ ...formData, [e.target.name]: e.target.value });
};
let onSubmit = (e) => {
e.preventDefault();
debugger;
var mailformat = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
setFormHelperText({
...formHelperText,
formHelperTextname: "",
formHelperTextemailid: "",
});
if (name.length === 0) {
setFormHelperText({
...formHelperText,
formHelperTextname: "Enter your name",
});
}
else if (emailid.length === 0) {
setFormHelperText({
...formHelperText,
formHelperTextemailid: "Enter your email",
});
} else if (!emailid.match(mailformat)) {
setFormHelperText({
...formHelperText,
formHelperTextemailid: "Enter valid email",
});
}
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<form className={classes.form} noValidate onSubmit={onSubmit}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="name"
label="Name"
name="name"
value={name}
onChange={onChange}
autoFocus
error={formHelperTextname.length > 0}
helperText={formHelperTextname}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="emailid"
value={emailid}
onChange={onChange}
autoComplete="email"
error={formHelperTextemailid.length > 0}
helperText={formHelperTextemailid}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
value={password}
onChange={onChange}
error={formHelperTextpassword.length > 0}
helperText={formHelperTextpassword}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
name="password2"
label="Retype Password"
type="password"
id="password2"
value={password2}
onChange={onChange}
error={formHelperTextpassword2.length > 0}
helperText={formHelperTextpassword2}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign Up
</Button>
<Grid container>
<Grid item xs></Grid>
<Grid item>
<Link href="/" variant="body2">
{"Already have an account? Sign In"}
</Link>
</Grid>
</Grid>
</form>
</div>
</Container>
);
}
When I'm trying to reset the value of formHelperTextname onSubmit function. The value is not updating to an empty string.
The value is set inside the IF condition but before the if condition when I try to reset the value of formhelperText it's not working
When I'm trying to reset the value of formHelperTextname onSubmit function. The value is not updating to an empty string.
The value is set inside the IF condition but before the if condition when I try to reset the value of formhelperText it's not working
States cannot be assigned immediately after they are changed. It is necessary to listen to State and do the same.
You can review the revised code below.
I hope I helped.
const [isClear, setIsClear] = useState(false);
useEffect(() => {
if (isClear) {
setFormHelperText({
...formHelperText,
formHelperTextname: "",
formHelperTextemailid: "",
});
}
}, [isClear]);
let onSubmit = (e) => {
e.preventDefault();
debugger;
var mailformat = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;
setIsClear(true);
if (name.length === 0) {
setFormHelperText({
...formHelperText,
formHelperTextname: "Enter your name",
});
}
else if (emailid.length === 0) {
setFormHelperText({
...formHelperText,
formHelperTextemailid: "Enter your email",
});
} else if (!emailid.match(mailformat)) {
setFormHelperText({
...formHelperText,
formHelperTextemailid: "Enter valid email",
});
}
};

How to apply Form validation for React Material-UI TextField and Select?

I'm trying to add validation to TextField and Select before going to handleNext(). Here is the code (2 components):
class Quote extends React.Component {
state = {
activeStep: 0,
zipCode: '',
destination: '',
sedanPrice: '',
suvPrice: '',
labelWidth: 0,
};
getStepContent = (step) => {
switch (step) {
case 0:
return (
<div>
<QuoteForm
{...this.state}
{...this.state.value}
handleChange={this.handleChange}
/>
</div>
)
case 1:
return (
<div>
<QuotePrice
{...this.state}
{...this.state.value}
/>
</div>
)
default:
throw new Error('Unknown step');
}
}
handleNext = () => {
this.setState(prevState => ({
activeStep: prevState.activeStep + 1,
}));
switch(this.state.activeStep){
case 0:
// Creates an API call for sedan pricing
API.getPrice(this.state.zipCode, "sedan" + this.state.destination).then(res => {
let price = res.data;
let key = Object.keys(price);
console.log("Sedan price is $" + price[key]);
this.setState({sedanPrice: price[key]});
})
.catch(err => console.log(err));
// Creates an API call for SUV pricing
API.getPrice(this.state.zipCode, "suv" + this.state.destination).then(res => {
let price = res.data;
let key = Object.keys(price);
console.log("SUV price is $" + price[key])
this.setState({suvPrice: price[key]});
})
.catch(err => console.log(err));
break
case 1:
console.log('forward to booking page');
window.location.href = '/booking';
break
default:
console.log('over');
}
};
handleBack = () => {
this.setState(state => ({
activeStep: state.activeStep - 1,
sedanPrice: '',
suvPrice: '',
destination: '',
zipCode: '',
}));
};
handleReset = () => {
this.setState({
activeStep: 0,
});
};
handleChange = event => {
const { name, value } = event.target;
this.setState({
[name]: value,
});
};
render() {
const { classes } = this.props;
const { activeStep } = this.state;
const steps = ['Pick Up Address', 'Select Your Vehicle'];
return (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<Paper className={classes.paper}>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your interest!
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{this.getStepContent(activeStep)}
<div className={classes.buttons}>
{activeStep !== 0 && (
<Button onClick={this.handleBack} className={classes.button}>
Back
</Button>
)}
<Button
variant="contained"
color="primary"
onClick={this.handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Book Now' : 'Next'}
</Button>
</div>
</React.Fragment>
)}
</React.Fragment>
</Paper>
</main>
</React.Fragment>
);
}
}
QuoteForm.js
export class QuoteForm extends React.Component {
state = {
zipCode: this.props.zipCode,
destination: this.props.destination,
}
render() {
const { classes } = this.props;
return (
<React.Fragment>
<Typography variant="h5" align="center">
Enter your zip code for a quick quote
</Typography>
<Grid container>
<Grid className={classes.TextField} item xs={12} sm={6}>
<TextField
required
id="zip"
name="zipCode"
label="Zip / Postal code"
fullWidth
autoComplete="billing postal-code"
value={this.props.zipCode}
onChange={this.props.handleChange}
/>
</Grid>
<FormControl xs={12} sm={6} className={classes.formControl}>
<Select
required
value={this.props.destination}
onChange={this.props.handleChange}
input={<Input name="destination" />}
displayEmpty
name="destination"
className={classes.selectEmpty}
>
<MenuItem value="">
<em>Select Your Airport *</em>
</MenuItem>
<MenuItem name="SAN" value={"SAN"}>San Diego International Airport</MenuItem>
<MenuItem name="LAX" value={"LAX"}>Los Angeles International Airport</MenuItem>
</Select>
</FormControl>
</Grid>
</React.Fragment>
);
}
}
I tried 2 different ways. First, using Button disabled and writing a function to handle the validation and set disabled to false. Second, using npm package to handle validation. Both failed since I'm new to this. Any help would be appreciated. Thanks in advance.
Do the following:
maintain a boolean state say error and errorMessage
in handleNext, validate he input values and set error to false and set a message to the error.
For material ui Textfield, use error and helperText props to set/display errors nicely beside your fields
For material ui Select, use FormControl error prop and provide label to Select in order to set/display errors nicely beside your fields
don't let the user go to next form until error is fixed.
pass error and errorMessage to QuoteForm component.
Working copy of your code is here in the codesandbox
state
state = {
activeStep: 0,
zipCode: "",
destination: "",
sedanPrice: "",
suvPrice: "",
labelWidth: 0,
error: false, //<---- here
errorMessage: {} //<-----here
};
handleNext
handleNext = () => {
let isError = false;
if (this.state.zipCode.length < 2) {
isError = true;
this.setState({
error: true,
errorMessage: { zipCode: "enter correct zipcode" }
});
}
if (this.state.destination === '') {
isError = true;
this.setState(prev => ({
...prev,
error: true,
errorMessage: { ...prev.errorMessage, destination: "enter correct destination" }
}))
} if(!isError){
//add else if for validating other fields (if any)
this.setState(prevState => ({
activeStep: prevState.activeStep + 1,
error: false,
errorMessage: {}
}));
}
...
Mui Textfield
<TextField
error={!!this.props.errorMessage.zipCode}
required
id="zip"
name="zipCode"
label="Zip / Postal code"
fullWidth
autoComplete="billing postal-code"
value={this.props.zipCode}
onChange={this.props.handleChange}
helperText={
this.props.errorMessage.zipCode &&
this.props.errorMessage.zipCode
}
/>
Mui Select use
<FormControl xs={12} sm={6} error={this.props.error}>
<Select
error={!!this.props.errorMessage.destination}
label="enter cor dest"
required
value={this.props.destination}
onChange={this.props.handleChange}
input={<Input name="destination" />}
displayEmpty
name="destination"
>
<MenuItem value="">
<em>Select Your Airport *</em>
</MenuItem>
<MenuItem name="SAN" value={"SAN"}>
San Diego International Airport
</MenuItem>
<MenuItem name="LAX" value={"LAX"}>
Los Angeles International Airport
</MenuItem>
</Select>
<FormHelperText>
{this.props.errorMessage.destination}
</FormHelperText>
</FormControl>

Resources