How to exclude special characters from a Textfield in React Hooks Form 7.0 - reactjs

<Controller
control={control}
name="txnId"
render={({ field }) => (
<MuiTextField
type="text"
required
id="txnId"
label="Payment Ref. No."
variant="outlined"
InputLabelProps={{
shrink: true,
}}
{...field}
/>
)}
/>
My useForm looks like this where I am setting the txnId. MuiTextField is the Material UI Textfields here
const { control, setValue, getValues} = useFormContext();
const methods = useForm({
defaultValues: {
txnId:""
}
});

I'm not sure but maybe it's be better to use controlled input instead od uncontrolled one like below:
const [state,setState] = useState({
txnId:""
});
and then use onchange to set value
const onChange = (e)=>{
const {value,name}=e.target;
//some logic to exclue char before setting in state
setState(s=>({...s,txnId:vakue});
}
<Controller
control={control}
name="txnId"
render={({ field }) => (
<MuiTextField
type="text"
required
id="txnId"
label="Payment Ref. No."
variant="outlined"
value={state.txnId}
onChange={onChange}
InputLabelProps={{
shrink: true,
}}
{...field}
/>
)}
/>

Related

mui autocomplete with react-hook-form: defaultValue in formData

I'm setting the defaultValue of the Autocopmlete component as below:
<Controller
control={control}
name={name}
render={({field: {onChange, value}}) => (
<Autocomplete
freeSolo={freeSolo}
options={options}
renderInput={params => {
return <TextField {...params} label={label} margin="normal" variant="outlined" onChange={onChange} />
}}
onChange={(event, values, reason) => onChange(values)}
defaultValue={defaultValue}
/>
)}
/>
the value is well displayed based on the defaultValue.
However when I click on the submit button, the value of the Autocomplete field is always undefined if I don't use the autocomplete component.
Here are how I register the hook and component (simplified code)
const customerSchema = yup.object().shape({
route: yup.string().nullable()
})
const {control, handleSubmit} = useForm({
resolver: yupResolver(customerSchema)
})
const onSubmit = formData => {
console.log(formData) // autocomplete is undefined if no action on the autocomplete
}
<form noValidate autoComplete="off" onSubmit={handleSubmit(onSubmit)}>
<AutoCompleteInput
control={control}
name="route"
label="route"
options={customers_routes.map(option => option.route_name)}
defaultValue={customer.route}
freeSolo={false}
/>
<Button type="submit">
Update
</Button>
</form>
What should I do to have the route field always available in the form data when I click on submit?
Why don't you use defaultValues option with useForm:
const {control, handleSubmit} = useForm({
resolver: yupResolver(customerSchema),
defaultValues: { route: customer.route },
});
and instead of sending defaultValue prop to AutoComplete you can use value prop, like this:
<Controller
control={control}
name={name}
render={({ field: { onChange, value } }) => (
<Autocomplete
freeSolo={freeSolo}
options={options}
renderInput={(params) => {
return (
<TextField
{...params}
label={label}
margin="normal"
variant="outlined"
onChange={onChange}
/>
);
}}
onChange={(event, values, reason) => onChange(values)}
value={value}
/>
)}
/>
Here is a simplest way to use an Autocomplete with react hook from , render your Autocomplete component inside Controller from react hook from, use onChange and value from the render function to control the value
<Controller
control={control}
name="type"
rules={{
required: 'Veuillez choisir une réponse',
}}
render={({ field: { onChange, value } }) => (
<Autocomplete
freeSolo
options={['field', 'select', 'multiple', 'date']}
onChange={(event, values) => onChange(values)}
value={value}
renderInput={(params) => (
<TextField
{...params}
label="type"
variant="outlined"
onChange={onChange}
/>
)}
/>
)}

react-hook-form not triggering onSubmit when using Controller

I have the following form:
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="voucherPrice"
control={control}
defaultValue={false}
rules={{ required: true }}
render={({ field: { onChange, value, ref } }) => (
<Input {...field} onChange={(ev) => handlePriceInputChange(ev)} value={price} type="number" innerRef={ref} />
)}
/>
<p>{errors.voucherPrice?.message}</p>
<Button
variant="contained"
sx={{ mt: 1, mr: 1 }}
type="submit"
>
{"Continue"}
</Button>
</form>
and with this configuration:
function PriceSelection(props) {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const onSubmit = (data) => {
console.log("does not work?", data);
};
const classes = useStylesPriceSelection();
const [selected, setSelected] = useState(false);
const [price, setPrice] = useState("");
const handlePriceInputChange = (ev) => {
console.log("change", price);
setPrice(parseInt(ev.target.value));
};
The function onSubmit does not trigger when I press the submit button. Also I would like the input field to be filled by default by the state price and its value to be sent with the parameter data on the function onSubmit when I push the submit button.
You are mixing useState with react-hook-form and are not updating react-hook-form's internal form state. You don't need to declare a useState for your field.
In your example you are destructering onChange from the field object of <Controller /> but you are never using it for your <Input /> component. Therefore react-hook-form can't update it's form state. As you set your field to be required the onSubmit callback won't get triggered because react-hook-form will never receive an update or value for it.
The correct way would be:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, onChange, value, ...field } }) => (
<Input {...field} onChange={onChange} value={value} type="number" innerRef={ref} />
)}
/>
Or even shorter:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, ...field } }) => (
<Input {...field} type="number" innerRef={ref} />
)}
/>
UPDATE
If you need to have access to the value outside of the <Controller />, you should use react-hook-form's watch method. This will allow you to subscribe to the latest value of the voucherPrice field and use it inside your component -> Docs
If you want to set or update the value programmatically you can use the setValue method from react-hook-form -> Docs
const { control, handleSubmit, watch, setValue } = useForm();
const voucherPrice = watch("voucherPrice");
const onButtonClick = () => {
setValue("voucherPrice", <newValue>);
}
If you really need to have a separate useState for your value and want to update it additionally to your react-hook-form field update, you could do the following:
<Controller
name="voucherPrice"
control={control}
rules={{ required: true }}
render={({ field: { ref, onChange, value, ...field } }) => (
<Input
{...field}
onChange={(v) => {
onChange(v);
handlePriceInputChange(v);
}}
value={value}
type="number"
innerRef={ref}
/>
)}
/>
But i would suggest to use the react-hook-form only solution, as it has all the functionality you need to manage your form state.

In the onSubmit event, how to pass the TextField Value without any value passed by the form React JS

I am new to react js and react hook.
I have three text fields in my form.
Ex: First Text Field value=5
Second Text Field value=3
Third Text Field value=FirstTextField-SecondTextField.
The first Text field value is the default value. But the second text field is editable. When I change the text field value. It's automatically updated to (based on calculation) text field third.
const formvalues = useForm({
mode: 'onSubmit',
reValidateMode: 'onChange',
defaultValues: {
workhrs:0,
remainhrs:0,
actualhrs:5
},
resolver: yupResolver(schema),
});
const { control, watch, reset, handleSubmit, onChange, formState, getValues } = methods;
const [workhrsvalue, setWorkhrsValue]=useState();
const [remainhrsvalue, setRemainhrsValue]=useState();
const handleTextChanged = (e) => {
var NewValue = parseFloat(e.target.value);
setWorkhrsValue(NewValue);
var remaininghrsValue=(parseFloat(actualhrs)-parseFloat(workhrs));
setRemainhrsValue(remaininghrsValue);
}
const onSubmit = async (data) => {
console.log(data);
<FormProvider {...formvalues}>
<form
noValidate
onSubmit={handleSubmit(onSubmit)}
className="flex flex-col md:overflow-hidden"
>
<Controller
render={({ field }) => (
<TextField
{...field}
id="actualhrs"
autoFocus={true}
variant="outlined"
placeholder="actualhrs"
/>
)}
name="actualhrs"
defaultValue="5"
control={control}
/>
<Controller
render={({ field }) => (
<TextField
{...field}
id="workhrs"
autoFocus={true}
variant="outlined"
placeholder="workhrs"
onChange={e => {
handleTextChanged(e)
field.onChange(e)
}}
/>
)}
name="workhrs"
defaultValue=""
control={control}
/>
<Controller
render={({ field }) => (
<TextField
{...field}
id="remainhrs"
autoFocus={true}
variant="outlined"
placeholder="remainhrs"
/>
)}
name="remainhrs"
defaultValue=""
control={control}
/>
</form>
</FormProvider>
ExpectedResult
I need to pass the Textfield3(remainhrs) value to submit event. But remainhrs value always coming undefined. How to resolve that.

reactjs: Es6 unable to understand the syntax

I am using react hook forms and encountered this example of using Controller for material ui TextField
({ field: { ref, ...field } }) => (
<TextField
{...field}
inputRef={ref}
fullWidth
required
label="Current Password"
type="password"
margin="dense"
/>
)
What does the below mean
({ field: { ref, ...field } })
and also {...field} (what it expands to)
<TextField
{...field}
inputRef={ref}
fullWidth
required
label="Current Password"
type="password"
margin="dense"
/>
The total code is
<Controller
name="old_password"
control={control}
render={({ field: { ref, ...field } }) => (
<TextField
{...field}
inputRef={ref}
fullWidth
required
label="Current Password"
type="password"
margin="dense"
/>
)}
/>
It's jus't a regular component... Think about it like this:
const Component = (props) =>{
const {ref, ...field} = props.field
return(
<TextField
{...field}
inputRef={ref}
fullWidth
required
label="Current Password"
type="password"
margin="dense"
/>
)
}
...field is just the spreaded original field props.field with ref property subtracted. In this case necessary cause TextField expects a ref to be hold by inputRef

react-hook-form(V7): How to pass a function via onChange to a nested Material UI component

I am have a Material UI nested component that look as follow:
imports . . .
const TxtInput = ({ name, value, label, required }) => {
const { control, ...rest } = useFormContext()
return (
<Controller
name={name}
defaultValue={value}
control={control}
render={({
field: { onChange, onBlur, value, name, ref }
}) =>
<TextField
required={required}
fullWidth
label={label}
id={name}
inputProps={{ 'aria-label': label }}
onBlur={onBlur}
onChange={onChange}
checked={value}
inputRef={ref}
{...rest}
/>}
/>
)
}
export default TxtInput
While in my app.js, <TxtInput /> look like this:
<FormProvider {...methods}>
<form onSubmit={handleSubmit(submit)}>
<TxtInput
name='fullName'
label='First and last name'
required
value=''
onChange={() => console.log('hello')}
</form>
</FormProvider>
And I am expecting to see 'Hello' with every keystroke in my console but, that is not the case.
Does anyone know why?
I think what you want is to pass the onChange event to the TxtInput instead of using its own Controller onChange
const TxtInput = ({ name, value, label, required, onChange }) => { // add onChange here
const { control, ...rest } = useFormContext()
return (
<Controller
name={name}
defaultValue={value}
control={control}
render={({
field: { onBlur, value, name, ref } // remove onChange here to allow pass though from parent onChange
}) =>
<TextField
required={required}
fullWidth
label={label}
id={name}
inputProps={{ 'aria-label': label }}
onBlur={onBlur}
onChange={onChange}
checked={value}
inputRef={ref}
{...rest}
/>}
/>
)
}
make a codesandbox to simulate your case as well. You can check it out
https://codesandbox.io/s/runtime-hill-9q2qu?file=/src/App.js
The last nested onChanged function should be returned as ()=>onChangeFn

Resources