React final form with datepicker validation - reactjs

Is there any way to display error message if the validation on the Field level fails when using react datepicker?
I am using datepicker with react final form:
const DatePickerAdapter = ({ input: { onChange, value }, ...rest }) => (
<DatePicker
selected={value}
onChange={(date) => {
console.log(date);
onChange(date);
}}
{...rest}
/>
);
And then I put into Field component from RFF:
<Field
name="date"
validate={required}
dateFormat="yyyy/MM/dd"
component={DatePickerAdapter}
/>
The issue is that it wont display any error if for example I leave the field empty or any part of validation is not passing. Is there a way to display this error message somehow in final form component?
Here is my codesandbox- other fields with validation can show error message but Field with datepicker is not:
https://codesandbox.io/s/react-final-form-third-party-components-example-datepicker-forked-wzrqgr?file=/index.js:2392-2579

my recommendation would be to use Formik and Yup. With Formik package use useFormik that will ask for initial values that would be empty string, validationSchema that would be from yup and lastly ask for onSubmit that is linked to button.
See a quick example in this url:
https://stackblitz.com/edit/react-ff8inu?file=src/App.js
This code will not work since the program is wrote inside Stackblitz react and not react native but idea stay the same

Related

react-hook-form custom uncontrolled inputs don't update their meta state (dirty, touched)

EDIT: solved by a react-hook-form module update.
Problem
react-hook-form does not update form input state dirty, touched on custom components where name is dynamically passed to register. Specifically, field array inputs where the name is something like ingredients.0.description will track the input value but not the input state. Simple names like question or name seem to behave correctly.
Reproduction of the bug on this CodeSandbox.io environment.
Steps to reproduce:
Type or change the value in the "name" field (on the first line)
Type or change the value in any of the "description" fields (the field array)
Open react-hook-form DevTools (the pink icon in the bottom right of the browser)
See that the ingredients fields did not update dirty or touched values despite not matching defaultValue and having blurred off the input
See that the name field shows dirty: true, touched: true correctly
Context
I'm using react-hook-form and running into problems when integrating it with a custom uncontrolled component.
In most (all?) of the examples I see, the register function is either applied to a native HTML Input Element as one or the other:
<input {...register("field_name")} />
<input ref={register} name="field_name" />
Because I have some custom input styling, I'd like to make reusable components that integrate into react-hook-form, and though I could do something like:
// Input.tsx
export function Input(props) {
type Props = {
type: string;
name: string;
};
export function Input(props: Props) {
const { type, name } = props;
const { register, getValues, formState } = useFormContext();
return <input type={type} {...register(name)} />;
}
// App.tsx
<FormProvider {...methods} >
<form onSubmit={handleSubmit(onSubmit)}>
<Input name="field_name" type="text" />
</form>
<FormProvider/>
Questions
Am I using register incorrectly?
Can register take a name dynamically or must it be a static string? Is my field array name description malformed?
Do uncontrolled component methods need to be applied directly to an <input /> or is it possible to wrap with a custom component and pass the props? What's the most idiomatic way to do this with react-hook-form?
How can I modify the code in my CodeSandbox to correctly reflect all field inputs' states?

Redux Form Semantic UI React Dropdown meta:touched not working

Redux Form Semantic UI React Dropdown meta:touched not working
My Redux form has two Semantic UI React Dropdown components. One dropdown the user selects a month (January thru December) and the other the user selects a year (2020 thru 2030). I have a requirement to validate that the month and year provider by the user is not in the past. For example, it is now May 2020 and if the user selects January 2020 an error needs to be shown to the user.
I’ve created a validator that properly works and creates an error for the above condition. The problem is that the Dropdown component’s “touched” meta is always false so the error is never displayed to the user.
Code for my DropdownInput component is shown below.
If a remove “touched” from the error label, the error displays immediately before the user has a chance to input their date… not a good user experience.
Any suggestions as to how to get the Dropdown component to update to “true” when the user makes a selection would be appreciated. I’ve also used the Semantic UI React Select component in place of the Dropdown component and have the same result.
Thanks in advance for your suggestions.
import React from 'react';
import { Form, Label, Dropdown } from 'semantic-ui-react';
const SelectInput = ({
input,
multiple,
options,
placeholder,
size,
style,
label,
meta: { touched, error },
}) => {
console.log(`DropdownInput: touched=${touched} error=${error}`);
return (
<Form.Field error={touched && !!error}>
{label && <label>{label}</label>}
<Dropdown
selection
value={input.value || null}
onChange={(e, data) => input.onChange(data.value)}
multiple={multiple}
options={options}
placeholder={placeholder}
size={size}
style={style}
/>
{touched && error && (
<Label basic color='red'>
{error}
</Label>
)}
</Form.Field>
);
};
export default SelectInput;

Rendering Formik Field outside Formik form

We have our own input components (like Checkbox, Textbox, or even CurrencyInput component)
We are now using Formik. So we replaced all <input... with <Field... in our components, eg.
const Checkbox = (props) => {
...
return (
<div className={myClass1}>
<Field type='checkbox' name={props.name} className={myClass2} ... />
<label ...>{props.label}</label>
</div>
)
};
Now the problem is, we can't have a standalone Checkbox outside a form anymore (eg. for an on-screen-only option). It will throw:
this.props.formik.registerField is not a function
We feel this is a dealbreaker. But before we ditch Formik and write our own form validation logics, I wonder if anyone else are having this dependency issue.
Is there really no way of rendering Formik Field outside Formik?
The Field component is what connects a form field to the Formik state. It uses context under the hood; Formik is the context provider and Field is the context consumer. Field is tied to Formik and has no use outside of it. For your use case where you want to render form fields that are sometimes connected to Formik and sometimes not, I would export two different components:
The base Checkbox component that has nothing to do with Formik. It should just use a normal input
A Field wrapper around that Checkbox component
While the Field component can take a type, causing it to render the corresponding input, it can also take a render prop to render whatever you want, and it is passed all of the state Formik manages for that field.
For example, your Checkbox and CheckboxField components could looks something like this:
const Checkbox = (props) => {
...
return (
<div className={myClass1}>
<input type='checkbox' checked={props.checked} onChange={props.onChange} />
<label ...>{props.label}</label>
</div>
)
};
const CheckboxField = (props) => {
return (
<Field name={props.name}>
{(field) => <Checkbox label={props.label} {...field} />}
</Field>
)
}
Now you use have two components that render exactly the same, but one is meant to be used within a Formik form (CheckboxField) and the other can be used anywhere (Checkbox).

Using a custom prop with Formik

I am using Formik in my application and i was wondering how to pass props and values to Sub Pages rendered by Formik.
I am implementing Formik like this
I have created a prop called handleSave
handleSave = (values) => {
console.log("Save clicked", values);
}
and trying to send it to Formik like this
<form
handleSave={() => (
this.handleSave(values);
)}
onSubmit={handleSubmit}
onBlur={handleBlur}
values={values}
>
But it was throwing React does not recognize thehandleSaveprop on a DOM element error, So, I sent it via Wiz and created a prop there in _renderPage(), this showed the prop and was clickable but the values weren't updated from Formik.
How do i solve it?

react | redux-form | material-ui | how to combine DatePicker with my form

After solving some problems, I stuck with sending DatePicker data to my form. In my form I use mostly elements from redux-form-material-ui, but DatePicker is not a part of it.
I found 2 ways of creating DatePicker component with redux-form.
<Field
name="startDate"
autoOk={true}
floatingLabelText="startDate"
component={(startDate) => {
return <DatePicker {...startDate} />;
}}
onChange={(event, date) => {console.log(date);}}
/>
and
<DatePicker
name="startDate"
autoOk={true}
floatingLabelText="startDate"
onChange={(event, date) => {console.log(date)}} />
The problem is that I don't know the way to update the form data with it. The first example even doesn't show the picked date in text field. I can see in form.myForm store, that I made date field active, but it is never updated with picked date. The second shows picked date, but it is not a part of form.myForm object...
I found some examples in internet (e.g. https://github.com/erikras/redux-form/issues/364 ) but there is no fields object in props, so cannot call this.props.fields.startDate.onChange.
I'm not sure what is a good way of working with redux-form and material-ui, as there is not many working examples. I started to think of making a wrapper to EVERY component I use, which will provide onChange method, which will update my store with any change made in form. But then I don't need redux-form anymore, so I think there must some other solution, I could use.
"react": "15.1.0",
"react-tap-event-plugin": "1.0.0",
"redux": "3.0.5",
"redux-form": "^6.0.0-alpha.4",
"redux-form-material-ui": "^2.0.0",
import React from 'react';
import DatePicker from 'material-ui/DatePicker';
export default ({ input, label, meta: { touched, error }, ...custom }) => {
return (
<DatePicker
onChange={(e, val) => {return input.onChange(val)}}
{...custom}
value={input.value}
/>
);
}
Considering this as in file renderDatePicker.js, usage would be,
<Field name="created_on" component={RenderDatePicker} floatingLabelText="Created Date"/>
Where Field is imported from redux-form.
Remember to provide {created_on: new Date('someiso8601')} in this.props.initialize to autopopulate it.
I used react-datepicker with redux form. The key was to set "selected" property correctly.
const selectedDate = this.props.fields.date.value ?
moment(this.props.fields.date.value, 'DD/MM/YYYY') :
moment();
<DatePicker
{...date}
className="form-control"
dateFormat="DD/MM/YYYY"
selected={selectedDate}
/>
Here is how I use it in my code.
<DatePicker
selected={dateField.value}
onChange={param => dateField.onChange(param)} />
dateField simply comes from:
const {fields: {dateField}, handleSubmit} = this.props;
Not just for this Datepicker but for any custom input, create a separate component to manage the input type and process. Which makes easy to feed your redux-form fields. This is the simple process I was taught by my senior developers when I was a Grad.
In your case, firstly import following additional libraries to your redux-form component
import moment from 'moment'
import { change } from 'redux-form' //We use the change to dispatch the own props of the redux-form component to resetDateField
Create a separate component by importing DatePicker in it. And your component will look something like this:
const datePickerInput = ({input,name,label,...props}) => {
return (
<div>
<label htmlFor={input.name}>
<span>
{label}
</span>
</label>
<div>
<DatePicker
className='form-control'
{...input}
{...props}
/>
</div>
</div>
)
}
Now feed this component to your redux-form field's component.
<Field
name = "startDate"
label = "Start Date"
dateFormat = 'MMM Do YY'
component={datePickerInput}
selected = {/*pass state value of startDate or pass some default null for startDate if nothing selected*/}
onChange={ (date) => {this.handleChangeStartDate(date, 'startDate')} } //bind this function in constructor and also setState value for your start date as null or some default
/>
the onChange function is to be handled something like this using moment:
handleChangeStartDate(date, target) {
const {resetDateField } = this.props
this.setState({
[target]: moment(date)
})
resetDateField('startDate', '' )
}
Now hook this resetDateField in your reduxForm #connect by passing dispatch and ownProps and returning resetDateField value expecting a dispatch of change for current form, field, and field value that you want to change using this resetDateField.

Resources