Checkbox onChange event is not handled by handleChange props by Formik - reactjs

I was building simple Form using React and Formik library.
I have added check box inside the form tag which is wrapped by withFormik wrapper of formik library.
I have tried to changing from
<input
type="checkbox"
name="flag"
checked={values.flag}
onChange={handleChange}
onBlur={handleBlur}
/>
to
<input
type="checkbox"
name="flag"
value={values.flag}
onChange={handleChange}
onBlur={handleBlur}
/>
but none is working.
the component is as following
import { withFormik } from 'formik';
...
const Form = props => (
<form>
<input
type="checkbox"
name="flag"
checked={props.values.flag}
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
<input
type="text"
name="name"
checked={props.values.name}
onChange={props.handleChange}
onBlur={props.handleBlur}
/>
</form>
);
const WrappedForm = withFormik({
displayName: 'BasicForm',
})(Form);
export default WrappedForm;
It should change props.values when clicking checkbox.
but it doesn't change props data at all.
Btw, it changes props data when typing in text input box.
This only happens with checkbox.

Using the setFieldValue from Formik props, you can set the value of the check to true or false.
<CheckBox
checked={values.check}
onPress={() => setFieldValue('check', !values.check)}
/>
My answer relates to react-native checkbox.
This article is very helpful. https://heartbeat.fritz.ai/handling-different-field-types-in-react-native-forms-with-formik-and-yup-fa9ea89d867e

Im using react material ui library, here is how i manage my checkboxes :
import { FormControlLabel, Checkbox} from "#material-ui/core";
import { Formik, Form, Field } from "formik";
<Formik
initialValues={{
check: false
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ values, setFieldValue }) => (
<Form className="gt-form">
<FormControlLabel
checked={values.check}
onChange={() => setFieldValue("check", !values.check)}
control={<Checkbox />}
label="save this for later"
/>
</Form>
)}
</Formik>

Related

What am I misunderstanding in my boolean radio group in Formik?

Following the Radio Group Example in the Formik docs and using Bootstrap 5 I've tried to create a boolean radio component that gets passed in a name and label. However, on render with the initialValues:
<Formik
initialValues={{
foo: false,
bar: false,
}}>
the no is selected because the initial value is set to false but whenever yes is chosen the radio will not fill in, component:
import React from 'react'
import PropTypes from 'prop-types'
import { Field } from 'formik'
const RadioBool = ({ name, label }) => {
const yesId = `${name}-yes`
const noId = `${name}-no`
return (
<>
<p id={`${name}-group-label`}>{label}:</p>
<div className="form-group mb-4" role="group" aria-labelledby={`${name}-group-label`}>
<div className="form-check">
<label htmlFor={yesId}>Yes</label>
<Field id={yesId} className="form-check-input" type="radio" name={name} value={true} />
</div>
<div className="form-check">
<label htmlFor={noId}>No</label>
<Field id={noId} className="form-check-input" type="radio" name={name} value={false} />
</div>
</div>
</>
)
}
RadioBool.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
}
export default RadioBool
but if checked is added to Yes, example:
<Field id={yesId} className="form-check-input" type="radio" name={name} value={true} checked />
the radio group works and I'm not sure why.
tests:
<RadioBool name="foo" label="Look at foo?" />
<RadioBool name="bar" label="Look at bar?" />
Research
How to add Radio Button in Formik Validations Reactjs?
How to create Radio buttons with Formik?
How to make use of Radio Group with useFormik Hook
how do you use onChange property on react formik radio field
formik radio button validation issues
Why does my boolean radio component not work in Formik unless checked is used on one <Field />?
The problem is described here Radio values must be strings, can't be numbers or booleans and as I see it's not solved 'from the box' yet.
In my TypeScript project I've created custom component. May it would be helpfull for you:
import React, { FC } from 'react';
type Props = {
name: string
value: boolean
checked: boolean
setValues: (values: React.SetStateAction<any>, shouldValidate?: boolean) => void;
}
const RadioButtonBooleanField: FC<Props> = ({name, value, checked, setValues}) => {
return (
<input type='radio' className="form-check-input" name={name} value={String(value)} checked={checked}
onChange={(e: any) => {
setValues((prevValues: any) => ({
...prevValues,
[e.target.name]: e.target.value === "true"
}))
}
}
/>
);
};
It can be used like this inside Formik component:
{({ errors, touched, values, setValues }) => (
<RadioButtonBooleanField name="IsExtendedView" value={false} checked={!values.IsExtendedView} setValues={setValues}/>
)}

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-hook-form reset is not working with Controller + antd

I'm trying to use react-hook-form together with the antd <Input /> component
I'm not getting reset to work with <Controller />
Here is my code:
const NormalLoginForm = () =>{
const {reset, handleSubmit, control} = useForm();
const onSubmit = handleSubmit(async ({username, password}) => {
console.log(username, password);
reset();
});
return (
<form onSubmit={onSubmit} className="login-form">
<Form.Item>
<Controller as={<Input
prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
autoFocus={true}
placeholder="Benutzername"
/>} name={'username'} control={control}/>
</Form.Item>
<Form.Item>
<Controller as={<Input
prefix={<Icon type="lock" style={{color: 'rgba(0,0,0,.25)'}}/>}
type="password"
placeholder="Passwort"
/>} name={'password'} control={control}/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
</Form.Item>
</form>
);
}
I'm expecting that the two input fields are getting cleared when the form is submitted. But that doesn't work.
Am I missing something here?
Example on Stackblitz
https://stackblitz.com/edit/react-y94jpf?file=index.js
Edit:
The RHFInput mentioned here React Hook Form with AntD Styling is now part of react-hook-form and has been renamed to Controller. I'm already using it.
I've figured out that chaning
reset();
to
reset({
username:'',
password:''
});
solves the problem.
However - I wanted to reset the whole form without explicitly assigning new values.
Edit 2:
Bill has pointed out in the comments that it's almost impossible to detect the default values for external controlled inputs. Therefore we're forced to pass the default values to the reset method. That makes totally sense to me.
You must wrapper the components for antd and create a render component, it is very similar if you use Material UI, So the code can be like:
import { Input, Button } from 'antd';
import React from 'react';
import 'antd/dist/antd.css';
import {useForm, Controller} from 'react-hook-form';
const RenderInput = ({
field: {
onChange,
value
},
prefix,
autoFocus,
placeholder
}) => {
return (
<Input
prefix={prefix}
autoFocus={autoFocus}
placeholder={placeholder}
onChange={onChange}
value={value}
/>
);
}
export const NormalLoginForm = () =>{
const {reset, handleSubmit, control} = useForm();
const onSubmit = ({username, password}) => {
console.log(username, password);
reset();
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="login-form">
<Controller
control={control}
name={'username'}
defaultValue=""
render={ ({field}) => (
<RenderInput
field={field}
autoFocus={true}
placeholder="Benutzername"
/>
)}
/>
<Controller
render={ ({field}) => (
<RenderInput
field={field}
type="password"
placeholder="Passwort"
/>
)}
defaultValue=""
name={'password'}
control={control}
/>
<Button
type="primary"
htmlType="submit"
className="login-form-button"
>
Log in
</Button>
</form>
);
}
export default NormalLoginForm;
You can notice that I did't put the Icon ,it was because I tested using the version 4 for antd and something change in how to use the icons.

How to use custom radio component with react-final-form?

I am trying to use a custom Radio component with React-final-form but it is not acting as a radio button but as a checkbox, ie, all the buttons are open for selection.
The 3rd party Radio button has the following schema:
checked boolean
Whether or not radio is checked
onChange () => void
Called when the user attempts to change the checked state
name string
The input name, used to reference the element in JavaScript
I created a custom Component for using the Radio Component:
const CustomRadio = (props: any) => (
<Radio
{...props.input}
{...props.rest}
name={props.name}
onChange={() => props.input.onChange()}
/>
)
and I am using it as follows:
<Field name="food"
component={CustomRadio}
value="1"
/>
<Field name="food"
component={CustomRadio}
value="2"
/>
Being very new to RFF and new to React, I may be doing something very wrong, hence any help will be appreciated.
Basically, I want to use RFF with my 3rd party components. Though I have been successful to use my Input component with RFF as expected, Radio Button is the one creating problems.
Here is the correct implementation for Radio with react-final-form:-
https://codesandbox.io/s/vibrant-easley-5n1ek?file=/index.js
/* eslint-disable jsx-a11y/accessible-emoji */
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import Radio from "#material-ui/core/Radio";
import FormLabel from "#material-ui/core/FormLabel";
const RadioWrapper = (props) => {
const {
input: { checked, value, name, onChange, ...restInput },
} = props;
return (
<Radio
name={name}
inputProps={restInput}
onChange={onChange}
checked={checked}
value={value}
/>
);
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const onSubmit = async (values) => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const App = () => {
return (
<Styles>
<h1>React Final Form - Simple Example</h1>
<a
href="https://final-form.org/react"
target="_blank"
rel="noopener noreferrer"
>
Read Docs
</a>
<Form
onSubmit={onSubmit}
initialValues={{
employed: false,
all_sub_tenants: "true"
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<FormControl component="fieldset">
<FormLabel component="legend">
Select Tenants
</FormLabel>
<RadioGroup aria-label="allSubTenants" name="allSubTenants">
<FormControlLabel
value="true"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"true"}
/>
}
label="All Sub-Tenants"
/>
<FormControlLabel
value="false"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"false"}
/>
}
label="Select Sub-Tenants"
/>
</RadioGroup>
</FormControl>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
</div>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
};
render(<App />, document.getElementById("root"));

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