Custom input validation in react-final-form - reactjs

I have set up a custom TimePicker component which I want to connect to react-final-form.
Form
<Form
onSubmit={onSubmit}
render={({ handleSubmit, form, submitting, pristine }) => (
<form onSubmit={handleSubmit}>
<Field
id="time"
name="time"
label="Time"
component={TimePicker.Adapter}
/>
<Button
disabled={submitting || pristine}
color="primary"
variant="contained"
type="submit"
>
Submit
</Button>
</form>
)}
/>
TimePicker
// Adapter for https://final-form.org/
const TimePickerAdapter = ({ input, meta, ...rest }) => (
<TimePicker
{...input}
{...rest}
value={input.value === '' ? null : input.value}
onChange={value => input.onChange(value)}
error={(meta.error || meta.submitError) && meta.touched}
errorText={meta.touched ? meta.error || meta.submitError : ''}
/>
);
// TimePicker implementation goes here..
function TimePicker(props) { ... }
TimePicker.Adapter = TimePickerAdapter;
export default TimePicker;
For external Field-Level-Validation I would add a validate prop to the <Field />. For example:
const required = value => (value ? undefined : 'Required')
<Field
id="time"
name="time"
label="Time"
validate={required}
component={TimePicker.Adapter}
/>
But I need an internal validation that gets passed to the <Form /> as well. For example the TimePicker is an input that expects values like 1000 (=> 10:00) but there is a input like 9999 which is obviously not a valid input since the maximum available time is 2359.
I would like to trigger a form error inside the custom input component/adapter. Is there a way to perform this?

Related

MUI v5: How can I auto focus form inputs with errors?

I am trying to make my form accessible.
Here is my sandbox link: https://codesandbox.io/s/typescript-material-ui-textfield-forked-0xh13?file=/src/App.tsx
My requirements are the following:
Upon submitting a form with validation errors, the 1st input with an error should be focused
Exactly like this form: https://a11y-guidelines.orange.com/en/web/components-examples/forms/
Is there an option in material ui to achieve this?
This is my code:
import React from "react";
import TextField from "#mui/material/TextField";
import { Form, Field } from "react-final-form";
const required = (value: string) =>
value ? undefined : "This field cannot be blank";
const App = () => (
<Form
onSubmit={(form_data) => console.log(form_data)}
render={({ handleSubmit, submitting }) => (
<form onSubmit={handleSubmit}>
<Field
name="line1"
validate={required}
render={({ input, meta }) => (
<TextField
{...input}
placeholder="Required"
label="Required"
helperText={meta.error}
error={meta.touched && meta.error}
/>
)}
/>
<Field
name="line2"
render={({ input, meta }) => (
<TextField
{...input}
placeholder="Optional"
label="Optional"
helperText={meta.error}
error={meta.touched && meta.error}
/>
)}
/>
<button onClick={handleSubmit}>Save</button>
</form>
)}
/>
);
export default App;
I ended up using a plugin for react-final-form called final-form-focus. I don't think there's anything for MUI
https://codesandbox.io/s/typescript-material-ui-textfield-forked-vep9e?file=/src/App.tsx

React-final-form focus doesn't focus on given field

I was trying to focus on the field when the user press the button, I used focus('fieldName'), but it seems doesn't work.
Below is codesandbox:
https://codesandbox.io/s/condescending-heisenberg-q8dcr?file=/src/App.jsx
As #erikras responded in GitHub issue:
That's not what form.focus() does. form.focus() tells Final Form that
a field has received focus.
You need an actual ref to the DOM node. Like this:
https://codesandbox.io/s/mystifying-mestorf-26yv8?file=/src/App.jsx
From codesandbox, we should const ref = useRef(); with Input
<Field name="firstName" type="text">
{({ input }) => (
<input {...input} placeholder="First Name" ref={ref} />
)}
</Field>
Then onClick:
<button
type="button"
onClick={() => {
ref.current.focus();
}}
disabled={submitting || pristine}
>
Focus
</button>

React final form - How to untouch field or hide error on onBlue

How to hide error on onBlur? I have an error validation before submitting, but I want to hide the error on onBlue. This is how I use form. I tried to change meta, but no results. Thank you.
<Form
initialValues={{ search }}
onSubmit={onSubmit}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="search" validate={composeValidators(required, minLength)}>
{({ input, meta }) => (
<div>
<SearchInputDumb {...input} submitSearch={handleSubmit}/>
{meta.error && meta.touched && (
<SearchFieldFooter>
<SearchStyledTipIcon />
<span>{meta.error}</span>
</SearchFieldFooter>
)}
</div>
)}
</Field>
</form>
)}
/>
You could have a isInputFocused state and make the error hide with that. In your SearchInputDumb component you could implement a onFocus/onBlur methods to change the isInoputFocused state

Other validation message is triggering instead of my message when using Ant design getFieldDecorator

I am using Ant design and this is my form when I click on save I am getting this type of validation msg instead of red bordered Antd validation msg
I want validation error like this which is shown in AntD documents.
https://codesandbox.io/s/do52z
I have writter my function like this
<Form id="myForm" onSubmit={this.handleSubmit}>
<Form.Item label="Code">
<CustomInput
form={this.props.form}
type="text"
disabled={this.state.disableFields}
name="code"
id="code"
placeholder=""
required={true}
errorMsg={"Please input code!"}
/>
</Form.Item>
</Form>
This is my custom Input
const CustomInput = ({
form, id, name, placeholder, required, errorMsg, type, disabled,}: Props) => {
return form.getFieldDecorator(id, {
rules: [
{
required: required,
message: errorMsg
}
]
})(
<Input
type={type}
name={name}
id={id}
disabled={disabled}
placeholder={placeholder}
className={name === "code" ? "code-input" : "input-box"}
/>
);
};
export default CustomInput;
and this is my save button
<Button
className="save-btn"
htmlType="submit"
form="myForm"
>
Save
</Button>
I think I am missing something little here. Thanks in advance
Ant design input doesn't have required prop..
Required prop should be give inside form.item rules prop.
Since you have given reqired to input tag it will cause Chrome to display a prompt that the user to fill out the field.
Update based on comment
Move formitem tag inside custominput component and try again.
<Form id="myForm" onSubmit={this.handleSubmit}>
<CustomInput
form={this.props.form}
type="text"
disabled={this.state.disableFields}
name="code"
id="code"
placeholder=""
required={true}
errorMsg={"Please input code!"}
/>
</Form>
..
const CustomInput = ({
form, id, name, placeholder, required, errorMsg, type, disabled,}: Props) => {
return(
<Form.Item label="Code">
{form.getFieldDecorator(id, {
rules: [
{
required: required,
message: errorMsg
}
]
})(
<Input
type={type}
name={name}
id={id}
disabled={disabled}
placeholder={placeholder}
className={name === "code" ? "code-input" : "input-box"}
/>
)}
</Form.Item>
)
};

React Datepicker with redux-form

How to make the react-datepicker bind with redux-form?
I have this redux-form field:
<Field name="due_date" component={props =>
<DatePicker
{...props}
readOnly={true}
selected={this.state.due_date}
value={this.state.due_date}
onChange={this.handleDueDate}
/>
} />
Whenever i submit the redux form does return an empty object not binding the datepicker's value...
my onChange :
handleDueDate(date) {
this.setState({
due_date: moment(date).format('L')
}, () => {
// do I need to dispatch and action here to update the redux-form in state tree?
})
}
you have to make a custom component to validate and use datepicker with redux-form
Try this
const datePicker = ({ input, label, type, className, selected, meta: { touched, error } }) => (
<div>
<div>
<DatePicker {...input}
selected={selected} placeholder={label}
type={type} className={className}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
/>
{touched && error && <span className="error_field">{error}</span>}
</div>
</div>
)
and then pass props to that custom component
<Field
name="date_of_birth"
component={datePicker}
type="text"
selected={this.state.date_of_birth}
onChange={this.handleChange.bind(this)}
className="form-control"
/>
For future readers, just go to this link: DatePicker in Redux Form
first, I created the component like metioned in link above and just passed the selected prop in it. in my case:
<Field
name="due_date"
component={DatePickerComponent}
selected={this.state.date_of_briefing} />

Resources