Password field showing "password is required" even after a value is passed - reactjs

I am working on a login form with Next Js as frontend and uses MUI 5. The issue is that even after i pass a value to password field, when i click on login button it is showing password field is required. Also when i try to console log the username and password to test it, only username got displayed in the console. please help me to understand what mistake I am doing. Please find the login form below
Please find the code MUI code for both username and password(I am making use of a purchased theme)
<form noValidate autoComplete='off' onSubmit={handleSubmit}>
<FormControl fullWidth sx={{ mb: 4 }}>
<Controller
name='Username'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<TextField
autoFocus
label='Username'
value={value}
onBlur={onBlur}
//onChange={onChange}
onChange={(e)=> setUsername(e.target.value)}
error={Boolean(errors.user)}
// placeholder='admin#materio.com'
/>
)}
/>
{errors.user && <FormHelperText sx={{ color: 'error.main' }}>{errors.user.message}</FormHelperText>}
</FormControl>
<FormControl fullWidth>
<InputLabel htmlFor='auth-login-v2-password' error={Boolean(errors.password)}>
Password
</InputLabel>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field: { value, onBlur } }) => (
<OutlinedInput
value={value}
onBlur={onBlur}
label='Password'
//onChange={onChange}
onChange={(e)=> setPassword(e.target.value)}
id='auth-login-v2-password'
error={Boolean(errors.password)}
type={showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onMouseDown={e => e.preventDefault()}
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOutline /> : <EyeOffOutline />}
</IconButton>
</InputAdornment>
}
/>
)}
/>
{errors.password && (
<FormHelperText sx={{ color: 'error.main' }} id=''>
{errors.password.message}
</FormHelperText>
)}
</FormControl>

Related

Tab Focuses endIcon instead of next field in Material UI TextField

Im using functional components and react hook forms with material ui
When resetting a password pressing tab i want to focus the next field instead of the endIcon.
i have tried using useRef but its not working.
Here is my code
<Controller
name="new_password"
control={control}
render={({ field }) => (
<TextField
{...field}
className="mt-8 mb-16"
type="password"
label="New Password"
error={!!errors.new_password}
helperText={errors?.new_password?.message}
variant="outlined"
fullWidth
required
onKeyUp={e => {
console.log('key pressed');
if (e.key === 'Tab') {
console.log('tab pressed');
confirmPassword.current.focus();
}
}}
autoComplete="off"
InputProps={{
className: 'pr-2',
type: showPassword ? 'text' : 'password',
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setShowPassword(!showPassword)}>
<Icon className="text-20" color="action">
{showPassword ? 'visibility' : 'visibility_off'}
</Icon>
</IconButton>
</InputAdornment>
)
}}
/>
)}
/>
<Controller
name="confirm_password"
control={control}
render={({ field }) => (
<TextField
{...field}
className="mt-8 mb-16"
type="password"
id="confirm_password"
label="Confirm Password"
error={!!errors.confirm_password}
helperText={errors?.confirm_password?.message}
variant="outlined"
ref={confirmPassword}
fullWidth
required
autoComplete="off"
InputProps={{
className: 'pr-2',
type: showConfirmPassword ? 'text' : 'password',
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setShowConfirmPassword(!showConfirmPassword)}>
<Icon className="text-20" color="action">
{showConfirmPassword ? 'visibility' : 'visibility_off'}
</Icon>
</IconButton>
</InputAdornment>
)
}}
/>
)}
/>
i did try using ref but its not working. is there a way around to achieve this.

setValue not working for react hookform with select

I am using react hook form. setValue is not working with select.I tried both in controller and in function but that doesnt work.Below is my code.
<Controller
name="mealkit"
control={control}
register={register}
defaultValue="Ready to eat"
setValue={selectedRow.mealkit}
rules={{ required: true, minLength: 4 }}
render={({ field }) => (
<Select
defaultValue="Ready to eat"
setValue={selectedRow.mealkit}
variant="outlined"
fullWidth
id="mealkit"
label="Mealkit"
inputProps={{ type: 'mealkit' }}
error={Boolean(errors.mealkit)}
helperText={
errors.mealkit
? errors.mealkit.type === "minLength"
? "mealkit should have atleast 4 letters"
: "mealkit is required"
: ""
}
{...field}
>
<MenuItem value={'Ready to eat'}>Ready to eat</MenuItem>
<MenuItem value={'Ready to cook'}>Ready to cook</MenuItem>
<MenuItem value={'Heat and eat'}>Heat and eat</MenuItem>
</Select>
)}
/>

Material-UI textfield and textlabel

I'm always a late adopter so this is my first time working with Material-ui and I love the aesthetics of it, but it's a lot more finicky than other UI frameworks I've used.
I have just a simple sign in 'card'. Just an email and password form, with a checkbox and a button. It looks great for the most part, but it's driving me nuts that the textfield label transition and animation works when it wants to. Right now the textfield label ends up shrunken on the top as if the input was focused, even when it's not... and then randomly it will work in the first input, but not the password input.
For the life of me I've tried every approach I can think of. My code is pasted below, and please if there's something else that might help diagnose this disorder let me know and I'll post that too.
<form className={classes.form} noValidate>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="login_email_input"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
classes={{ root: classes.textFieldRoot }}
value={formData.email}
// value=""
// InputLabelProps={{
// shrink: inputState.email,
// // shrink: false,
// }}
onSelect={(e) => setInputState({ email: true, password: false })}
onChange={(e) => handleChange(e)}
/>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
autofocus
name="password"
label="Password"
type="password"
id="login_password_input"
autoComplete="current-password"
classes={{ root: classes.textFieldRoot }}
value={formData.password}
// InputLabelProps={{
// focused: inputState.password,
// shrink: !Boolean(inputState.password),
// }}
onChange={(e) => handleChange(e)}
onSelect={(e) => setInputState({ email: false, password: true })}
/>
<FormControlLabel
control={
<Checkbox
value={formData.rememberMe}
name="rememberMe"
onChange={(e) => handleChange(e)}
color="primary"
disabled={!validated}
/>
}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
classes={{ root: classes.submit, label: classes.buttonText }}
>
Sign In
</Button>
</form>

react-hook-form with react select

Someone has a working sample with a react-hook-form with a react-select? In below the Select with id="accountId" works. However I need it to be a required field. I tried adding:
innerRef={register({ required: true })}
But that did not work. AFAIK this is because the Select needs to be wrapped in a Controller (correct me if I am wrong).
So I tried adding the Controler where id="accountId2". But now I get error:
Uncaught TypeError: Cannot read property 'split' of undefined
I am looking for a small sample where the Select will be integrated with the form and required fields.
<Container>
<Form onSubmit={handleSubmit(onSubmit)}>
<FormGroup>
<div>
<Controller
as={<Select
name="accountId2"
id="accountId2" />}
options={options}
control={control}
/>
</div>
</FormGroup>
<FormGroup>
<Label for="exampleCheckbox">Choose account to update</Label>
<div>
<Select
name="accountId"
id="accountId"
innerRef={register({ required: true })}
isDisabled={isNewAccount}
ref={selectInputRef}
isClearable={true}
placeholder="Search for an existing account number or click new account below"
label="Single select"
options={options}
defaultValue=""
/>
</div>
Yes, In order for Select to work with RHF, you need to wrap it in a controller like this.
<Controller
as={
<Select>
{options.map((option, index) => (
<MenuItem key={index} value={option}>
{option}
</MenuItem>
))}
</Select>
}
name={options_name}
control={control}
defaultValue=""
rules={{ required: true }}
/>
So it worked for me by adding the following attribute to the controller.
rules={{ required: true }}
Hope this answers your question.
If you are using react-hook-form: "^7.19.1", can be used as below.
<Controller
control={control}
name="test"
render={({
field: { onChange, onBlur, value, name, ref },
fieldState: { invalid, isTouched, isDirty, error },
formState,
}) => (
<Select
onBlur={onBlur}
onChange={onChange}
inputRef={ref}
className={classes.textField}
fullWidth
input={<Input id="name" />}
defaultValue={"science"}
>
{tags.map((tag, index) => (
<MenuItem key={index} value={tag}>
{tag}
</MenuItem>
))}
</Select>
)}
/>

react-hook-form and MUI FormControl

So I am trying to register some radio buttons for my form, however it will not register.
<FormControl component="fieldset" inputRef={register({ required: true })}>
<FormLabel component="legend">Promoting</FormLabel>
<RadioGroup aria-label="promoting" name="promoting" value={promoting} onChange={handleChange} inputRef={register({ required: true })}>
<FormControlLabel value="business" control={<Radio />} label="Business" />
<FormControlLabel value="nonprofit" control={<Radio />} label="Non-Profit" />
<FormControlLabel value="event" control={<Radio />} label="Event" />
</RadioGroup>
</FormControl>
I am wondering what I am doing wrong
Full code:
export default function BuildAd() {
const [promoting, setValue] = React.useState('female');
const handleChange = (event) => {
setValue(event.target.value);
};
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => console.log(data);
console.log(errors);
return (
<div style={{ padding: 16, margin: 'auto', maxWidth: 600 }}>
<CssBaseline />
<Typography variant="h5" align="center" component="h2" gutterBottom>
Create your campaign
</Typography>
<Paper style={{ padding: 16 }}>
<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" placeholder="First name" name="First name" ref={register({required: true, maxLength: 80})} />
<input type="text" placeholder="Last name" name="Last name" ref={register({required: true, maxLength: 100})} />
<input type="text" placeholder="Email" name="Email" ref={register({required: true, pattern: /^\S+#\S+$/i})} />
<input type="tel" placeholder="Mobile number" name="Mobile number" ref={register({required: true, minLength: 6, maxLength: 12})} />
<select name="Title" ref={register({ required: true })}>
<option value="Mr">Mr</option>
<option value="Mrs">Mrs</option>
<option value="Miss">Miss</option>
<option value="Dr">Dr</option>
</select>
<input name="Developer" type="radio" value="Yes" ref={register({ required: true })}/>
<input name="Developer" type="radio" value="No" ref={register({ required: true })}/>
<Typography variant="h5">What are you Advertising</Typography>
<Box m={2}/>
<FormControl component="fieldset" inputRef={register({ required: true })}>
<FormLabel component="legend">Promoting</FormLabel>
<RadioGroup aria-label="promoting" name="promoting" value={promoting} onChange={handleChange} inputRef={register({ required: true })}>
<FormControlLabel value="business" control={<Radio inputRef={register({ required: true })} />} label="Business" />
<FormControlLabel value="nonprofit" control={<Radio inputRef={register({ required: true })} />} label="Non-Profit" />
<FormControlLabel value="event" control={<Radio inputRef={register({ required: true })} />} label="Event" />
</RadioGroup>
</FormControl>
<input type="submit" />
</form>
</Paper>
</div>
);
}
You can fallback on controllable components by using Controller if it doesn't work.
In your case, I suspect it's because the name props passed to your RadioGroup is not the same as the name attribute when passed into native inputs like input or select.
react-hook-form V7
const { handleSubmit, control } = useForm({
defaultValues: {
promoting2: '',
},
});
<FormControl component="fieldset">
<FormLabel component="legend">Promoting</FormLabel>
<Controller
rules={{ required: true }}
control={control}
name="promoting2"
render={({ field }) => (
<RadioGroup {...field}>
<FormControlLabel
value="business"
control={<Radio />}
label="Business"
/>
<FormControlLabel
value="nonprofit"
control={<Radio />}
label="Non-Profit"
/>
<FormControlLabel
value="event"
control={<Radio />}
label="Event"
/>
</RadioGroup>
)}
/>
</FormControl>
react-hook-form V6
const { register, handleSubmit, errors, control } = useForm({
promoting: '',
});
const onSubmit = (data) => alert(JSON.stringify(data, null, 2));
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl component="fieldset">
<FormLabel component="legend">Promoting</FormLabel>
<Controller
rules={{ required: true }}
control={control}
name="promoting"
as={
<RadioGroup>
<FormControlLabel
value="business"
control={<Radio />}
label="Business"
/>
<FormControlLabel
value="nonprofit"
control={<Radio />}
label="Non-Profit"
/>
<FormControlLabel
value="event"
control={<Radio />}
label="Event"
/>
</RadioGroup>
}
/>
</FormControl>
<input type="submit" />
</form>
If you want to read the value when onChange fires, you cannot do that when passing the element to the as props:
<Controller
{...}
as={
<MyComponent
onChange={handleChange} // handleChange will never be called
/>
}
/>
The reason is because Controller will copy the element that you pass in and pass its own onChange props that will override yours. See here and here.
To fix that problem, you need to use another way to pass the element down by using render props to gain more control on how you should render your components.
<Controller
rules={{ required: true }}
control={control}
name="promoting2"
render={({ name, onBlur, onChange, value }) => (
<RadioGroup
value={value}
onBlur={onBlur}
onChange={(e) => {
onChange(e);
console.log(e.target.value); // will be called this time
}}
>
<FormControlLabel
value="business"
control={<Radio />}
label="Business"
/>
{...}
</RadioGroup>
)}
/>

Resources