react-hook-form and react-datetime: How to set the time to moment() from a button - react-hook-form

I am using react-datetime inside a react-hook-form
I want the user to easily set the time to current time using a button Immediate. Instead of selecting the current time manually.
I am trying the below
const [currentDateTime, setcurrentDateTime] = useState(null);
<Controller
name="resetDateTime"
control={control}
required
render={({ field }) => (
<Datetime
onChange={setcurrentDateTime}
inputProps={{
placeholder: "MM-DD-YYYY HH:mm",
}}
value={currentDateTime}
viewMode="time"
/>
)}
/>
<Button color="primary" className="ml-1" onClick={() => setcurrentDateTime(moment())}>
{"Immediate"}
</Button>
The problem is onSubmit the react-hook-form I get resetDateTime = undefined
How to implement this properly. So I can use the Immediate button and also submit form and get the resetDateTime value

You're mixing RHF with your local state currentDateTime and are not linking the. field to RHF as you're missing to spread the field object to your <Datetime /> component.
The correct way would be to use RHF's setValue to update your resetDateTime field and get rid of the useState hook.
const { control, handleSubmit, setValue } = useForm();
<Controller
name="resetDateTime"
control={control}
required
render={({ field }) => (
<Datetime
{...field}
inputProps={{
placeholder: "MM-DD-YYYY HH:mm",
}}
viewMode="time"
/>
)}
/>
<Button color="primary" className="ml-1" onClick={() => setValue("resetDateTime", moment())}>
{"Immediate"}
</Button>

Related

react-hook-form validate that password match (failing)

I am using react-hook-form to validate that my password and confirm password are the same. For some reason, the form elements aren't validating. I confirmed with a console.log that the reference and the confirm password are the same, but it is failing anyways. It all seems fine, where have I gone wrong?
Code
const { setValue, register, getValues, handleSubmit, watch, formState: { errors } } = useForm();
const password = useRef({});
password.current = watch("password", "");
const selectType = watch("type", '');
<IonItem >
<IonLabel position="floating">Password</IonLabel>
<IonInput type="password" {...register("password", { required: 'Password is required' })}/>
</IonItem>
<IonItem >
<IonLabel position="floating">Confirm Password</IonLabel>
<IonInput type="password" {...register("password_repeat", { validate: value => value === password.current || "The passwords do not match" })}/>
</IonItem>
The problem is that the interface for <IonInput /> is different from the one register expects. With the spreading of register you're linking an onChange handler to update RHF's form state of that field. <IonInput /> uses a change handler called ionChange instead.
As a rule of thumb you should use RHF's <Controller /> when working with external controlled components.
const { control, handleSubmit, watch, formState: { errors } } = useForm();
const password = watch("password", "");
<Controller
control={control}
name="password"
rules={{ required: "Password is required" }}
render={({ field }) => (
<IonItem>
<IonLabel position="floating">Password</IonLabel>
<IonInput
value={field.value}
ionChange={field.onChange}
ionBlur={field.onBlur}
onFocus={field.onFocus}
ref={field.ref}
type="password"
/>
</IonItem>
)}
/>
<Controller
control={control}
name="password_repeat"
rules={{
required: "Password is required",
validate: (value) =>
value === password|| "The passwords do not match"
}}
render={({ field }) => (
<IonItem>
<IonLabel position="floating">Password</IonLabel>
<IonInput
value={field.value}
ionChange={field.onChange}
ionBlur={field.onBlur}
onFocus={field.onFocus}
ref={field.ref}
type="password"
/>
</IonItem>
)}
/>

react hook form: as vs render: unable to understrand the syntax and how are they same

I have seen in react hook forms using as and also render
Eg:
<Controller
render={({ field }) => <input {...field} />}
name="firstName"
control={control}
defaultValue=""
/>
or
<Controller
as={<input .. />}
name="firstName"
control={control}
defaultValue=""
/>
whats the difference
<Controller/> is good to use with there is an external controlled component such (e.g. Material-UI) to wrap the whole component and control is easier.
render is useful when you want to customise the external component while as is just renders the original component. An example of using render could be:
import { TextField } from '#mui/material';
import { Controller } from 'react-hook-form';
const FormTextField = ({
label,
name,
...props
}) => {
return (
<Controller
name={name}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
label={label}
error={!!error}
helperText={error ? error?.message : ''}
/>
)}
{...props}
/>
);
};
As you can see, render gives you ability to access different values (such as error) in the Material UI component which is not easy to do with as.
Read more about what properties you have access in render at https://react-hook-form.com/api/usecontroller/controller
This example is also helpful: https://codesandbox.io/s/react-hook-form-v7-controller-5h1q5

react-datepicker and react-hooks-form get value displayed in datepicker without time zone

I am using react-datepicker and react-hook-form. But my picker add time zone to the result:
Is there anyway to ensure that the picker just returns the value provided in the picker with out adding timezone?
const FormDatePicker = props => {
return (
<>
<Label for="exampleEmail">{props.label}</Label>
<Controller
as={
<DatePicker
isClearable
name={props.name}
className={"form-control"}
showTimeSelect
timeFormat="HH:mm"
timeIntervals={15}
timeCaption="time"
dateFormat="dd-MM-yyyy H:mm"
autoComplete="Off"
/>
}
control={props.control}
rules={{ required: false }}
valueName="selected"
onChange={([date]) => date}
name={props.name}
placeholderText="Select date"
defaultValue={null}
/>
</>
);
};

Dynamic name for react-final-form Field

I have 2 forms. When I choose an option on 1st form, the 2nd form is added to the page with the parameters retrieved from backend. Now how can I set the parameter names as react-final-form Field names?
I could not find a way to do this. Where to pass the parameter names?
<Form
onSubmit={onSubmit}
validate={validate}
React Final Form calls your onSubmit function with the values from all the fields in your form. It's totally up to you to transmit the values to your server.
If you're asking how to build the second form, you just add the fields you need to add. So, say you got back from the server that you needed three fields: [ 'name', 'startTime', 'endTime' ]. You'd just loop through that array and add the fields.
<Form onSubmit={onSubmit}>({handleSubmit}) => (
<form onSubmit={handleSubmit}>
{fieldsFromServer.map(fieldName => (
<div key={fieldName}>
<label>{fieldName}</label>
<Field name={fieldName} component="input"/>
</div>
))}
</form>
)}<Form>
Does that help? You don't have to "pass parameters to the form", you just add the Field components that you need.
Call the FinalForm like
<FinalFieldArrayForm onSubmit={this.handleSubmitTemplate} fieldsFromServer={parameters} />
and FinalForm is
import React from "react";
import ReactDOM from "react-dom";
import { Form, Field } from 'react-final-form'
import arrayMutators from 'final-form-arrays'
import { FieldArray } from 'react-final-form-arrays'
import "./styles.css";
const FinalForm = ({onSubmit, fieldsFromServer}) => (
<Form
onSubmit={onSubmit}
mutators={{
// potentially other mutators could be merged here
...arrayMutators
}}
render={({
handleSubmit,
form: {
mutators: { push, pop }
},
pristine,
form,
submitting,
values
}) => (
<form onSubmit={handleSubmit}>
<div className="buttons">
<button type="button" onClick={() => push('records', undefined)}>+</button>
<button type="button" onClick={() => pop('records')}>-</button>
<button type="button" onClick={form.reset} disabled={submitting || pristine}>Reset</button>
</div>
<FieldArray name="records">
{ ({fields}) => (
<div>
{fields.map( (name, index) => (
<div key={`${name}.${index}`}>
<label>{index + 1}</label>
{fieldsFromServer.map( param => <Field key={`${name}.${param}`} name={`${name}.${param}`} component="input" placeholder={`${name}.${param}`} /> )}
<button type="button" onClick={() => fields.remove(index)}>-</button>
<button type="button" onClick={() => fields.insert(index+1)}>+</button>
</div>
))}
</div>
)}
</FieldArray>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>Submit</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
)
const rootElement = document.getElementById("root");
ReactDOM.render(<FinalForm onSubmit={() => (<div/>)} fieldsFromServer={["firstName", "lastName"]} />, rootElement);

Unable to access mutator functions in Wizard form page while using react-final-form

I am trying to create a Wizard form using react-final-form by referring to this code https://codesandbox.io/s/km2n35kq3v. For my use case I need some mutator functions to be used inside my form fields. This example illustrates how to do that - https://codesandbox.io/s/kx8qv67nk5?from-embed.
I am not sure how to access mutator functions in my form steps when I am using a wizard form instead of a single page form.
I tried to combine both the examples by modifying the <Form> component rendered by Wizard.js to pass in the mutators. However I cannot access these mutators in the Wizard form pages.
In Wizard.js
return (
<Form
mutators={{
// potentially other mutators could be merged here
...arrayMutators,
}}
render={({
handleSubmit,
submitting,
values,
pristine,
invalid,
form: {
mutators: {push, pop, remove},
},
}) => {
return (
<form onSubmit={handleSubmit}>
Another file index.js
<Wizard
initialValues={{ employed: true, stooge: "larry" }}
onSubmit={onSubmit}
>
<Wizard.Page>
<FieldArray name="customers">
{({ fields }) =>
fields.map((name, index) => (
<div key={name}>
<label>Cust. #{index + 1}</label>
<Field
name={`${name}.firstName`}
component="input"
placeholder="First Name"
/>
<span
onClick={() => fields.remove(index)}
style={{ cursor: "pointer" }}
>
❌
</span>
</div>
))
}
</FieldArray>
</Wizard.Page>
</Wizard>
It errors out - remove is undefined in index.js
Look at this working example: https://codesandbox.io/s/znzlqvzvnx
changes I have made:
Wizard.js
static Page = ({ children, mutators }) => {
if(typeof children === 'function'){
return children(mutators);
}
return children;
};
...
<form onSubmit={handleSubmit}>
{
// activePage
<activePage.type {...activePage.props} mutators={mutators} />
}
...
index.js (only first <Wizard.page>)
<Wizard.Page>
{
({ upper }) => (
<React.Fragment>
<div>
<label>First Name</label>
<Field
name="firstName"
component="input"
...
</div>
</React.Fragment>
)
}
</Wizard.Page>

Resources