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

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

Related

Custom input validation in react-final-form

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?

Problem in Conditional rendering with react-final-form formState

Here my react code.
<Form
onSubmit={this.onSubmit}
initialValues={formInitialValues}
render={({ hasValidationErrors }) => (
<form onSubmit={handleSubmit}>
<Field
label="First name"
name="firstName"
component={TextInput}
validate={...validate callback function...}
/>
{hasValidationErrors
? <button type="button">Proceed</button>
: <div>Some Content</div>}
</form>
)
/>
Using hasValidationErrors for my condition but the page keep stucked and throw
Error code: SIGILL
I found the problem was using formState.

Specify initial value for radio button

I want to the "Exact" radio button to be checked when a form is opened:
<Form
onSubmit={onSubmit}
initialValues={{ match_type: "exact" }}
render={({ handleSubmit, form, reset, submitting, pristine, values }) => (
<form
onSubmit={() => {
handleSubmit();
}}
>
<fieldset>
<legend>Match type</legend>
<Field name="match_type">
{({ input }) => (
<label>
<input {...input} type="radio" value="fuzzy" /> Fuzzy
</label>
)}
</Field>
<Field name="match_type">
{({ input }) => (
<label>
<input {...input} type="radio" value="exact" /> Exact
</label>
)}
</Field>
</fieldset>
<button type="submit">Save match</button>
</form>
)}
/>
The radio button remains unchecked. Any idea how I should get this to work? Note using <Field component="input" type="radio" .../> is not an option for me.
Codesandbox: https://codesandbox.io/s/react-final-form-reset-after-submit-forked-q6jyv?file=/index.js:359-1235
You can set the default to be checked in the tag.
<input {...input} type="radio" value="exact" checked />
I just needed to use the Field component properly:
<Field name="match_type" type="radio" value="fuzzy">
{({ input }) => (
<label>
<input {...input} /> Fuzzy
</label>
)}
</Field>
This way the <input will get what it needs spread in from the argument to the render prop.
If you inspect your component in codesandbox provided, you can see that Field component doesn't have value prop. I'm attaching a screenshot here
You have a few options to solve this. The main idea though is to understand what you are passing when you say {...input} In your Field component, you currently only have name prop, so you can add something like this
input={{ name: 'match_type', value: 'exact', onChange: (e) => (whatever you need on change) }}
RFF could be tricky with just setting value like that since source of truth lives in the form. So, you can also use a mutator functionality of the form. This is a good description of how to do it

Input loses focus when using custom input for Formik Field in FieldArray

I am using custom input components to handle my form data, and noticed strange behaviour. Only when I am using FieldArray with custom input components the input loses focus as I type.
Here is the form setup:
<Formik
enableReinitialize
initialValues={{ ...getInitialState() }}
onSubmit={(values, actions) => {
save(values, actions)
}}
validationSchema={schema}
>
{({ values, isSubmitting, setFieldValue, dirty }) => (
...
<Images />
...
)}
</Formik>
And inside my Images component
import { imageState } from "states"
import Input from "form/input"
function Images() {
...
return (
<div className={styles.wrapper}>
<FieldArray
name="images.posters"
render={({ form, push, remove }) => {
const images = form.values.images.poster
return (
<>
<button onClick={() => push(imageState)}>Add Poster</button>
{images.map((image, index) => (
<div key={index} className={styles.imageGroup}>
<Field //using custom input loses focus
name={`images.poster.${index}.src`}
component={Input}
/>
<Field //using Formik default component doesn't loose focus
name={`images.poster.${index}.src`}
/>
<button onClick={() => remove(index)}>Remove Poster</button>
</div>
))}
</>
)}}
/>
</div>
)
}
Is there another way I have to use custom inputs for FieldArray? I do not experience this problem when I am not using FieldArray.

Material-UI and Redux-form not styling when being mapped

I've created this codesandbox - https://codesandbox.io/s/pk8p4lvl90
I can implement the material-ui instructions (https://redux-form.com/7.2.2/examples/material-ui/) fine without the mapping mechanism, but as soon as I apply the mapping I can't get the material-ui to implement the look for a textfield.
In my example I have commented out the code I have tried that works without mapping being involved.
Form -
<form onSubmit={handleSubmit}>
<div>
{/* <Field
name="firstName"
component={renderTextField}
label="First Name"
/>*/}
<FieldArray
name="firstName"
component={renderTextField}
label="First Name"
/>
</div>
</form>
TextField Render -
const renderTextField = ({ fields, input, label }) => (
<div>
{fields.map((newIntel, index) => (
{/* <TextField
name={newIntel}
key={index}
label={label}
placeholder={label}
component="input"
placeholder={label}
label={label} /> */}
<Field
name={newIntel}
key={index}
label={label}
placeholder={label}
component="input"
placeholder={label}
label={label}
/>
))}
<div
variant="fab"
color="primary"
className="jr-fab-btn"
aria-label="add"
onClick={() => fields.push()}
>
Click me
</div>
</div>
);
In order to use redux-form features with material-ui look, you need use redux-form's input component with render function that will return material-ui's component with appropriate props. You started doing so, but renderTextField should look a little bit differently, e.g.:
const renderTextField = ({
input,
label,
meta: { touched, error },
...custom
}) => (
<TextField
hintText={label}
floatingLabelText={label}
errorText={touched && error}
{...input}
{...custom}
/>
)
Having this, you can reuse it in, let's say renderForm function:
const renderForm = ({ fields, input, label }) => (
<div>
{fields.map((newIntel, index) => (
<Field
...
component={renderTextField}
...
/>
))}
...
</div>
);
That's based on what I've found in the redux-form Docs you linked. Take another look there as well, it's well described there as well.

Resources