I'm trying to reset the inputs in my formik Form on submit. It seems I'm supposed to use resetForm() to do that but i get the error:
src\components\CommentSubmition\inCommentSubmition.js
Line 19:13: 'resetForm' is not defined no-undef
Here's my component:
import React from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import {createComment} from '../../services/CommentLocalStorage.js'
import * as Yup from 'yup';
function CommentForm(props){
return (
<Formik
initialValues={{ autor: '', content: ''}}
validationSchema={Yup.object({
autor: Yup.string().required('Required'),
content: Yup.string().required('Required')
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
createComment(props.pageEnum, props.articleId, values.autor, values.content)
setSubmitting(false);
},400);
resetForm();
}}
>
<Form>
<label htmlFor="autor">Nome</label>
<Field name="autor" type="autor" placeholder="Nome"/>
<ErrorMessage name="autor" />
<br/>
<label htmlFor="content">Comentário</label>
<Field name="content" type="content" placeholder="Comentário" />
<ErrorMessage name="content" />
<br/>
<button type="submit">Submit</button>
</Form>
</Formik>
);
};
export default CommentForm;
It seems most people make something like this:
const formik = some configuration
And then they use it like
formik.resetForm()
And instead I'm using the Formik component with all the stuff inside it (I did it based on an example available on the official tutorials). If possible i'd like to keep it like that and still make the form reset.
Pass resetForm as a parameter to your onSubmit function. That should give your function access to the resetForm method from Formik thereby getting rid of the error and successfully reset the form. If you want to use any methods from the formik library inside your onSubmit function, first pass a parameter to the function so you can have access to the formik method. Let me know if this helps
import React from 'react';
import { Formik, Field, Form, ErrorMessage } from 'formik';
import {createComment} from '../../services/CommentLocalStorage.js'
import * as Yup from 'yup';
function CommentForm(props){
return (
<Formik
initialValues={{ autor: '', content: ''}}
validationSchema={Yup.object({
autor: Yup.string().required('Required'),
content: Yup.string().required('Required')
})}
onSubmit={(values, { setSubmitting, {resetForm }) => { //<--- See here for code added
setTimeout(() => {
createComment(props.pageEnum, props.articleId, values.autor, values.content)
setSubmitting(false);
},400);
resetForm();
}}
>
<Form>
<label htmlFor="autor">Nome</label>
<Field name="autor" type="autor" placeholder="Nome"/>
<ErrorMessage name="autor" />
<br/>
<label htmlFor="content">Comentário</label>
<Field name="content" type="content" placeholder="Comentário" />
<ErrorMessage name="content" />
<br/>
<button type="submit">Submit</button>
</Form>
</Formik>
);
};
export default CommentForm;
Related
I am new to react and I have just started using Formik
I like how simple it makes making forms and handling forms in react.
I have created multiple custom fields using formik, I am putting the react-select field I created as an example here.
import { ErrorMessage, Field } from "formik";
import React from "react";
import Select from 'react-select'
const SelectInput = (props) => {
const { label, name, id,options, required, ...rest } = props;
const defaultOptions = [
{label : `Select ${label}`,value : ''}
]
const selectedOptions = options ? [...defaultOptions,...options] : defaultOptions
return (
<div className="mt-3">
<label htmlFor={id ? id : name}>
{label} {required && <span className="text-rose-500">*</span>}
</label>
<Field
// className="w-full"
name={name}
id={id ? id : name}
>
{(props) => {
return (
<Select
options={selectedOptions}
onChange={(val) => {
props.form.setFieldValue(name, val ? val.value : null);
}}
onClick = {(e)=>{e.stopPropagation}}
{...rest}
// I want someting like onReset here
></Select>
);
}}
</Field>
<ErrorMessage
name={name}
component="div"
className="text-xs mt-1 text-rose-500"
/>
</div>
);
};
export default SelectInput;
This is the usual code I use for submitting form as you can see I am using resetForm() method that is provided by formik, I want to attach the reseting logic in on submit method itself.
const onSubmit = async (values, onSubmitProps) => {
try {
//send request to api
onSubmitProps.resetForm()
} catch (error) {
console.log(error.response.data);
}
};
If you want to reset the selected value after the form is submitted, you need to provide a controlled value for the Select component.
The Formik Field component provides the value in the props object, so you can use it.
For example:
SelectInput.js
import { ErrorMessage, Field } from 'formik';
import React from 'react';
import Select from 'react-select';
const SelectInput = ({ label, name, id, options, required, ...rest }) => {
const defaultOptions = [{ label: `Select ${label}`, value: '' }];
const selectedOptions = options ? [...defaultOptions, ...options] : defaultOptions;
return (
<div className='mt-3'>
<label htmlFor={id ? id : name}>
{label} {required && <span className='text-rose-500'>*</span>}
</label>
<Field
// className="w-full"
name={name}
id={id ? id : name}
>
{({
field: { value },
form: { setFieldValue },
}) => {
return (
<Select
{...rest}
options={selectedOptions}
onChange={(val) => setFieldValue(name, val ? val : null)}
onClick={(e) => e.stopPropagation()}
value={value}
/>
);
}}
</Field>
<ErrorMessage name={name} component='div' className='text-xs mt-1 text-rose-500' />
</div>
);
};
export default SelectInput;
and Form.js
import { Formik, Form } from 'formik';
import SelectInput from './SelectInput';
function App() {
return (
<Formik
initialValues={{
firstName: '',
}}
onSubmit={async (values, { resetForm }) => {
console.log({ values });
resetForm();
}}
>
<Form>
<SelectInput
name='firstName'
label='First Name'
options={[{ label: 'Sam', value: 'Sam' }]}
/>
<button type='submit'>Submit</button>
</Form>
</Formik>
);
}
export default App;
Therefore, if you click the Submit button, value in the Select component will be reset.
You can also make a useRef hook to the Fromik component and then reset the form within the reset function without adding it as a parameter to the function.
https://www.w3schools.com/react/react_useref.asp
It's one of the really nice hooks you'll learn as you progress through React :)
So if I understood you correctly you want to reset a specif field value onSubmit rather than resetting the whole form, that's exactly what you can achieve using actions.resetForm().
Note: If nextState is specified, Formik will set nextState.values as the new "initial state" and use the related values of nextState to update the form's initialValues as well as initialTouched, initialStatus, initialErrors. This is useful for altering the initial state (i.e. "base") of the form after changes have been made.
You can check this in more detail here.
And here is an example of resetting a specific field using resetForm() whereby you can see as you input name, email and upon submit only email field will get empty using resetForm.
import "./styles.css";
import React from "react";
import { Formik } from "formik";
const initialState = {
name: "",
email: ""
};
const App = () => (
<div>
<h1>My Form</h1>
<Formik
initialValues={initialState}
onSubmit={(values, actions) => {
console.log(values, "values");
actions.resetForm({
values: {
email: initialState.email
}
});
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
/>
<br />
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.email}
name="email"
/>
<br />
<br />
{props.errors.name && <div id="feedback">{props.errors.name}</div>}
<button type="submit">Submit</button>
</form>
)}
</Formik>
</div>
);
export default App;
I am using Yup and Formik for my Sign up Form.
I want to show an appropriate error based on my validation using YUP.
Below is my Code.
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from "yup";
function ValidationSchemaExample() {
const SignupSchema = Yup.object().shape({
name: Yup.string()
.min(2, 'Too Short!')
.max(70, 'Too Long!')
.required('Required'),
});
function handleOnSubmit(values){
console.log("Values : " , values)
}
return(
<div>
<Formik
initialValues={{
name: '',
email: '',
}}
validationSchema={SignupSchema}
validateOnChange={false}
validateOnBlur={false}
onSubmit={handleOnSubmit}
>
{({ errors, touched }) => (
<Form id="submit_add_bom_form">
<Field name="name" />
{errors.name && touched.name ? (
<div>{errors.name}</div>
) : null}
<ErrorMessage name="name" />
</Form>
)}
</Formik>
<button form="submit_add_bom_form" type="submit">Submit</button>
</div>
)
}
export default ValidationSchemaExample
It shows me 2 times "Required" text instead of 1 time.
When I click on submit button and if there is any error then it shows me twice instead of once.
Any help would be great.
It's because of this part:
// Error will be shown when there's an error for "name" and if the
// field is touched
{errors.name && touched.name ? (<div>{errors.name}</div>) : null}
<ErrorMessage name="name" />
Either remove that condition or <ErrorMessage /> component
I'm usign Formik to validate some data fields with Semantic UI in React. It works fine with input fields but doesn't work with selectors.
How it works with input fields:
import { Formik, Form, Field } from 'formik';
import { Input, Button, Select, Label, Grid } from 'semantic-ui-react';
import * as Yup from 'yup';
...
const initialValues = {
name: ''
};
const requiredErrorMessage = 'This field is required';
const validationSchema = Yup.object({ name: Yup.string().required(requiredErrorMessage) });
<Formik
htmlFor="amazing"
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={values => this.handleSubmit(values)}>
{({ errors, touched }) => (
<Form id="amazing">
<div>
<CreationContentContainer>
<Grid>
<Grid.Column>
<Label>Company name</Label>
<Field name="name" as={Input} placeholder="name" /> // here is the input
<div>{touched.name && errors.name ? errors.name : null}</div>
</Grid.Column>
</Grid>
</CreationContentContainer>
<Button type="submit" form="amazing">
Create company
</Button>
</div>
</Form>
)}
</Formik>;
However, when the as={Input} is replaced by as={Select}, it doesn't work. The dropdown gets opened when I click on the selector, it shows the options (company1 and company2), I click on one of them but it does not work -> the value shown is still the placeholder value.
import { Formik, Form, Field } from 'formik';
import { Input, Button, Select, Label, Grid } from 'semantic-ui-react';
import * as Yup from 'yup';
const companyOptions = [ // the select's options
{ text: 'company1', value: 'company1' },
{ text: 'company2', value: 'company2' },
];
<Formik
htmlFor="amazing"
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={values => this.handleSubmit(values)}>
{({ errors, touched }) => (
<Form id="amazing">
<div>
<CreationContentContainer>
<Grid>
<Grid.Column>
<Label>Company name</Label>
<Field
name="name"
as={Select} // here is changed to Select
options={companyOptions} // the options
placeholder="name"
/>
<div>{touched.name && errors.name ? errors.name : null}</div>
</Grid.Column>
</Grid>
</CreationContentContainer>
<Button type="submit" form="amazing">
Create company
</Button>
</div>
</Form>
)}
</Formik>;
The reason is because Formik passes an onChange function into the component. However, the Select (which is just syntactic sugar for dropdown https://react.semantic-ui.com/addons/select/) onChange prop uses a function of shape handleChange = (e: React.SyntheticEvent<HTMLElement>, data: SelectProps) => this.setState({value: data.value}) (https://react.semantic-ui.com/modules/dropdown/#usage-controlled) which is different than the conventional handleChange = (event: React.SyntheticEvent<HTMLElement>) => this.setState({value: event.target.value}) which formik uses.
So an easy solution would be to use the Formik function setFieldValue.
In your code, the implementation would be something like this:
const companyOptions = [ // the select's options
{ text: 'company1', value: 'company1' },
{ text: 'company2', value: 'company2' },
];
<Formik
htmlFor="amazing"
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={values => this.handleSubmit(values)}>
{({ errors, touched, setFieldValue, values }) => {
const handleChange = (e, { name, value }) => setFieldValue(name, value));
return (
<Form id="amazing">
<div>
<CreationContentContainer>
<Grid>
<Grid.Column>
<Label>Company name</Label>
<Field
name="name"
as={Select} // here is changed to Select
options={companyOptions} // the options
placeholder="name"
onChange={handleChange}
value={values.name}
/>
<div>{touched.name && errors.name ? errors.name : null}</div>
</Grid.Column>
</Grid>
</CreationContentContainer>
<Button type="submit" form="amazing">
Create company
</Button>
</div>
</Form>
)}
}
</Formik>;
Here's a somewhat working version using your code. The fields update (verified with a console.log), but the submit button isn't working 🤷♂️: https://codesandbox.io/s/formik-and-semanticui-select-gb7o7
This is a somewhat incomplete solution and does not handle the onBlur and other injected formik functions. It also defeats the purpose of Formik somewhat. A better solution would be to create a HOC that wraps semantic ui components to use Fromik correctly: https://github.com/formium/formik/issues/148.
And lastly, you can skip the Semantic UI Select and use the Semantic UI HTML controlled select: https://react.semantic-ui.com/collections/form/#shorthand-field-control-html. Notice the select vs Select. This will work natively with Formik without the need to pass in onChange and value.
I recently created a binding library for Semantic UI React & Formik.
Link: https://github.com/JT501/formik-semantic-ui-react
You just need to import Select from the library and fill in name & options props.
// Import components
import { Select, SubmitButton } from "formik-semantic-ui-react";
const companyOptions = [ // the select's options
{ text: 'company1', value: 'company1' },
{ text: 'company2', value: 'company2' },
];
<Formik
htmlFor="amazing"
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={values => this.handleSubmit(values)}>
{({ errors, touched }) => (
<Form id="amazing">
<div>
<CreationContentContainer>
<Grid>
<Grid.Column>
<Label>Company name</Label>
<Select
name="name"
selectOnBlur={false}
clearable
placeholder="name"
options={companyOptions}
/>
</Grid.Column>
</Grid>
</CreationContentContainer>
<SubmitButton>
Create company
</SubmitButton>
</div>
</Form>
)}
</Formik>;
I have a separate module that I'm working on, this module is meant to contain formik supporting HTML input elements.
The issue is I'm unable to use the useFields() hook since my module component doesn't connect to the formik context.
Here's my component that resides in a different module:
import React from "react";
import PropTypes from "prop-types";
import { useField } from "formik";
export function TextField({ label, ...props }) {
const [field, meta] = useField(props);
return <input {...field} {...meta} />;
}
TextField.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string,
showErrors: PropTypes.bool
};
TextField.defaultProps = {
label: "",
showErrors: true
};
export default TextField;
and here is my Formik form:
<Formik
initialValues={{
firstName: "firstName"
}}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{formik => (
<Form>
<TextField name="firstName" />
<button type="submit">Submit</button>
</Form>
)}
</Formik>
No matter what I do I get the following error:
TypeError: Cannot read property 'getFieldProps' of undefined
Anyone have an idea what I'm doing wrong?
Looking at the useField docs I would expect:
<input {...field} {...props} />
The input component does not expect the {...meta} props.
other than that I could not reproduce your error.
I am in the process of learning React. I tried the Formik package https://www.npmjs.com/package/formik for React. It seems to work nice.
However, I tried to understand how it actually works with no luck.
Here is an example of simple form made with Formik:
import React from 'react';
import { Formik, Form, Field } from 'formik';
const FormikShort = () => (
<div>
<h1>Formik example</h1>
<Formik
initialValues={{email: '', password: ''}}
validate={values => {
let errors = {};
if (!values.email) {
errors.email = 'Required field';
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Not valid email address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ errors, touched, isSubmitting}) => (
<Form noValidate>
<div className="form-group">
<label htmlFor="emailLabel">Input email address</label>
<Field className="form-control" type="email" name="email" />
{errors.email && touched.email && errors.email}
</div>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
export default FormikShort;
So in the example above there is an anonymous function call between Formik-element opening and closing tags. What makes this possible?
If I create my own simple component, such as
function Dummy(props) {
return <h1>Dummy component: {props.text}</h1>;
}
And then have it rendered like this
<Dummy
text="hello"
>
<div>Some text</div>
</Dummy>
the text "Some text" is not rendered at all. What do I have to do in order to be able insert stuff inside my own component and have it show up?
What about the function call inside the Formik-elements opening and closing tags? Where do the values for parameters (errors, touched, isSubmitting) come from?
I tried to look at the source files at node_modules/formik but I don't know exactly what file to look at. There are a lot of files, such as:
formik.cjs.development.js
formik.cjs.production.js
formik.esm.js
formik.umd.development.js