How to make form inputs interdependent in ReactJS - 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

Related

TextField mui component autoFocus end of text

Right now, autoFocus applies to the beginning of the input but I'd like to get focused on the end of the text.
export default function BasicTextFields() {
const [value, setValue] = React.useState(
"hello world. hello world. hello world"
);
return (
<Box
component="form"
sx={{
"& > :not(style)": { m: 1, width: "25ch" }
}}
noValidate
autoComplete="off"
>
<TextField
id="outlined-basic"
variant="outlined"
value={value}
onChange={(e) => setValue(e.target.value)}
multiline
autoFocus
/>
</Box>
);
}
Is this possible?
I tried this from this link : https://github.com/mui/material-ui/issues/12779
But this didn't work for my case.
<TextField
variant="outlined"
type="text"
id="field-comment"
name="comment"
label="Label"
placeholder="Placeholder"
onChange={(event) => setValue(event.target.value)}
inputRef={(input) => input && input.focus()}
onFocus={(e) =>
e.currentTarget.setSelectionRange(
e.currentTarget.value.length,
e.currentTarget.value.length
)}
multiline
rows={4}
value={value}
className={classes.sCommentTextField}
/>
I also tried this.
<TextField
inputRef={input => input && input.focus()}
/>
but it also didn't work.
Are there any ways that I can do this?
This works!
<TextField
variant="outlined"
type="text"
id="field-comment"
name="comment"
label="Label"
placeholder="Placeholder"
onChange={(event) => setValue(event.target.value)}
inputRef={(input) => input && input.focus()}
onFocus={(e) =>
e.currentTarget.setSelectionRange(
e.currentTarget.value.length,
e.currentTarget.value.length
)}
multiline
rows={4}
value={value}
className={classes.sCommentTextField}
/>
Remove autoFocus and add inputRef and onFocus

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>

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>

How to clear input fields after submit in react

so i'm creating my portfolio and i am now on the final page, the contact page. I have it almost finished. I have it hooked up with emailjs and i receive emails with the message inputted as expected.
The problem i'm having is, when the form is submitted, i don't know how to clear the UI input fields. I could disregard using e.preventDefault(), however, i would like to keep that, as i want to style the page if the desired result has been achieved(message sent), or if an error has occurred. I would like to mention that i had used state for the name, email and message beforehand, however, i was unable to use the state variables in conjunction with the emailjs syntax, more specifically, with the "e.target" section. When the form is submitted, the result is the message being sent to my email, with the text inputted by the user still in the input fields.
The code is below, with some names left as hidden for privacy reasons:
import React, { useState } from 'react'
import { Box, Grid, Typography, Button} from '#material-ui/core'
import Navbar from './Navbar';
import Styles, { InputField } from './Styles'
import SendIcon from '#material-ui/icons/Send'
import emailjs from 'emailjs-com'
function Contact() {
const classes = Styles()
function sendEmail(e) {
e.preventDefault()
emailjs.sendForm('gmail', 'hidden', e.target, 'hidden')
.then((result) => {
console.log(result.text);
result.text ==="OK" ? console.log("it worked") : console.log("didnt work")
}, (error) => {
console.log(error.text);
});
}
return (
<Box component='div'>
<Navbar/>
<Grid container justify='center'>
<Box component='form' className={classes.contactContainer} onSubmit={sendEmail}>
<Typography variant='h5' className={classes.contactHead}>Contact Me</Typography>
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<InputField
id="email"
name="email"
fullWidth={true}
label="Email"
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<InputField
id="message"
name="message"
fullWidth={true}
label="Enter Message Here"
multiline
rows={8}
variant="outlined"
margin='dense'
size='medium'
/>
<br/>
<Button
type="submit"
variant='outlined'
fullWidth={true}
endIcon={<SendIcon/>}
className={classes.contactButton}>
Contact Me
</Button>
</Box>
</Grid>
</Box>
)
}
export default Contact
For the simplest way to do it in your code, use useState to declare initial value of the fields such as:
const [name, setName] = useState("");
Then you need to set the "value" param in your InputField component, eg:
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
value={name}
/>
And after receiving the result in emailjs.sendForm, use setName to reset the value of the name field, eg:
setName("")
Use the similar method for other fields.
Thank you for the answer, it helped, however did not fully fix the problem. That being said, i was able to find a solution. I used the onChange param and passed through a function which changes the state AND the value. Also, after receiving the result in emailjs.sendForm, i reset the value of all the fields.
const handleChange = (event) => {
event.target.name=="name"
? setName(event.target.value)
: event.target.name=="email"
? setEmail(event.target.value)
: event.target.name=="message"
? setMessage(event.target.value)
: console.log("error")
};
function sendEmail(e) {
e.preventDefault()
emailjs.sendForm('gmail', 'hiddenForPrivacy', e.target, 'hiddenForPrivacy')
.then((result) => {
console.log(result.text);
result.text ==="OK" ? console.log("it worked") : alert("didnt work")
setName("")
setMessage("")
setEmail("")
}, (error) => {
console.log(error.text);
});
}
The input fields now look like this:
return (
<Box component='div'>
<Navbar/>
<Grid container justify='center'>
<Box component='form' className={classes.contactContainer} onSubmit={sendEmail}>
<Typography variant='h5' className={classes.contactHead}>Contact Me</Typography>
<InputField
id="name"
name="name"
fullWidth={true}
label="Name"
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={name}
/>
<br/>
<InputField
id="email"
name="email"
fullWidth={true}
label="Email"
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={email}
/>
<br/>
<InputField
id="message"
name="message"
fullWidth={true}
label="Enter Message Here"
multiline
rows={8}
variant="outlined"
margin='dense'
size='medium'
onChange={(e) => handleChange(e)}
value={message}
/>
<br/>
<Button
type="submit"
variant='outlined'
fullWidth={true}
endIcon={<SendIcon/>}
className={classes.contactButton}>
Contact Me
</Button>
</Box>
</Grid>
</Box>

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