Material-UI textfield and textlabel - reactjs

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>

Related

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

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>

react-hook-form undo the form to previous state

i populated a form with react-hook-form's setValue function (i don't know if it is the best way to set up a form in edit mode).
Once the form was touched from a user, i want (on a button click) to restore the form to the state i've previously setted,
(pay attention that i don't want to reset it but, make it again to the value i've previously setted)
const { register, handleSubmit, watch, reset, errors, setValue } = useForm();
const { id } = useParams()
const { loading, error, data } = useQuery(GET_FBUSER,{
variables: {_id: id},
skip: id === undefined
});
useEffect(() => {
if (data) {
const {_id, id, fbId, name} = data.FBUser[0]
setValue('_id',_id);
setValue('id',id);
setValue('fbId',fbId);
setValue('name',name);
}
}, [data])
<form onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={3}>
<Grid item xs={4}>
<TextField fullWidth inputRef={register} InputLabelProps={{ shrink: true }} InputProps={{readOnly: true}} name="_id" label="_Id" variant="outlined" />
</Grid>
<Grid item xs={8}>
<TextField fullWidth inputRef={register} InputLabelProps={{ shrink: true }} InputProps={{readOnly: true}} name="id" label="Id" variant="outlined" />
</Grid>
<Grid item xs={12}>
<TextField fullWidth inputRef={register} InputLabelProps={{ shrink: true }} name="name" label="Name" variant="outlined" />
</Grid>
<Grid item xs={12}>
<TextField fullWidth error={errors.fbId} inputRef={register({required : true})} InputLabelProps={{ shrink: true , required: true}} name="fbId" label="Facebook Id" variant="outlined" />
</Grid>
<Grid item xs={12}>
<TextField fullWidth inputRef={register} InputLabelProps={{ shrink: true }} name="note" label="Note" variant="outlined" />
</Grid>
<Grid item xs={12}>
<Button type="submit" variant="contained" color="primary" startIcon={<SaveIcon/>}>Salva</Button>
<Button onClick={reset} variant="contained" color="primary" startIcon={<CancelIcon/>}>Annulla</Button>
</Grid>
</Grid>
</form>
You should pass an object with form fields values in reset method.
reset({
type: "contact",
firstName: "John",
lastName: "Doe"
})
If you set default initial values in useForm hook, invoking reset() result in form fields setted to your initial values, but if you pass an object with different data, the fields are setted to values you passed.
So in your case you should save the form state in a particular moment, maybe with getValues(), then on button click set the values you wanted.
Docs:
Reset - React Hook Form
Example:
Reset Example - Codesandbox

How to make form inputs interdependent in ReactJS

I'm practicing to create an app similar to those of peer-2-peer lending, to give a better idea here is a screen.
Lending Application
So, loan size and amount represent the same data: the amount of money you want to get. I would like to know how to connect the input amount with the slider, so that the latter moves according to the amount typed and vice versa.
Also I would like the interest rate to increase by a factor of X as the amount requested increases and vice versa.
Form code:
......
<div className="form-group">
<label htmlFor="size">Loan size</label>
<Typography id="discrete-slider-always" gutterBottom>
Min.
</Typography>
<Slider
defaultValue={550}
min={100}
max={1000}
aria-labelledby="discrete-slider-always"
step={1}
valueLabelDisplay="on"
/>
<TextField
id="standard-read-only-input"
label="Interest rate"
defaultValue="25%"
InputProps={{
readOnly: true,
}}
/>
<FormControl fullWidth variant="outlined">
<InputLabel htmlFor="outlined-adornment-amount">Amount</InputLabel>
<OutlinedInput
id="size"
name="size"
value={tutorial.size}
onChange={handleInputChange}
startAdornment={<InputAdornment position="start">$</InputAdornment>}
labelWidth={60}
/>
</FormControl>
......
I hope I was as clear as possible!
Do something like this:
const X_FACTOR = 0.045;
const [amount, setAmount] = React.useState(550);
const handleAmountChange = (value) => {
setAmount(value);
};
<Slider
defaultValue={550}
min={100}
max={1000}
aria-labelledby="discrete-slider-always"
step={1}
value={amount}
onChange={(e, value) => handleAmountChange(value)}
valueLabelDisplay="on"
/>
<TextField
id="standard-read-only-input"
label="Interest rate"
defaultValue="25%"
value={`${Math.ceil(amount * X_FACTOR)}%`}
InputProps={{
readOnly: true
}}
/>
<FormControl fullWidth variant="outlined">
<InputLabel htmlFor="outlined-adornment-amount">Amount</InputLabel>
<OutlinedInput
id="size"
name="size"
value={amount}
onChange={(e) => handleAmountChange(e.target.value)}
I created a sandbox to show my solution: https://codesandbox.io/s/agitated-torvalds-ed2s7?file=/src/App.tsx

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>
)}
/>

semantic-ui-react: Does large dataset in Form.Select makes the Form slow?

I am having below form(inside modal) created using semantic-ui-react.
<Modal open={editBasicModal} size="small">
<Modal.Header>Your basic details</Modal.Header>
<Modal.Content scrolling>
<Form loading={isSubmitting}>
<Form.Group inline widths="equal">
<Form.Input
required
label="First Name"
fluid
type="text"
name="firstName"
value={values.firstName}
onChange={handleChange}
error={errors.firstName !== undefined}
/>
<Form.Input
required
label="Last Name"
fluid
type="text"
name="lastName"
value={values.lastName}
onChange={handleChange}
error={errors.lastName !== undefined}
/>
</Form.Group>
<Form.TextArea
label="Bio"
type="text"
name="bio"
value={values.bio}
onChange={handleChange}
rows={3}
error={errors.bio !== undefined}
/>
<Form.Select
label="Country"
name="location.country"
placeholder="Country"
value={values.location.country}
onChange={(e, { value }) => {
setFieldValue("location.country", value);
}}
options={this.state.allCountries}
/>
</Form>
</Modal.Content>
<Modal.Actions open={true}>
<Button type="submit" onClick={handleSubmit} >
Update
</Button>
</Modal.Actions>
</Modal>
The above code is from a component which uses Formik + yup.
this.state.allCountries is an array of 200+ records. Now this is making my form slow, the typing inside textarea and input are very slow.
As per my findings the large dataset in the Form.Select is causing the issue, because if i replace the options={this.state.allCountries} to options={[ { key: 1, value: "india", text: "india"} ]}, everything starts working fine. Or if I delete the Form.Selectthen also form works fine.
Few questions?
Is it a known issue?
what are the possible solutions?
I figured out that this is a problem with Form.Select. I changed it with select and everything worked smoothly then. Here is the updated code for select:
<Form.Field >
<label htmlFor="location.country">Country</label>
<select
name="location.country"
id="location.country"
value={values.location.country }
onChange={event => {
setFieldValue("location.country", event.target.value);
}}
>
<option key={0} value={undefined}>
-select-
</option>
{this.state.allCountries}
</select>
</Form.Field>
This renders similar(somewhat) select element with no slowness issue.
Hope it would help someone.

Resources