jaredpalmer / formik Goto Github PK
View Code? Open in Web Editor NEWBuild forms in React, without the tears ๐ญ
Home Page: https://formik.org
License: Apache License 2.0
Build forms in React, without the tears ๐ญ
Home Page: https://formik.org
License: Apache License 2.0
Continuing #58 .
@pauloabmiranda suggested having setXX's accept a path to field to be updated a la Lodash's _.set
method.
Currently _.set
is mutative, an so we either need to copy state first and then call it on the copy or come up with a different implementation
Good first contrib. Someone can copy the Prettier setup from razzle
Hi :)
What's the best way to pass the errors from outside?
What I'm trying to do is to get network errors from the redux store.
Hey,
first the ball, thanks for nice form library.
I'm struggling with enzyme. I want to test that bad input values are properly validated.
After simulate submit on <form>
with enzyme, Formik component have state isSubmitting == true, and my validationSchema is ignored.
Here is the code of my form component:
// component/form/index.js
import React from "react";
import { Formik } from "formik";
import Yup from "yup";
const SimpleForm = ({
values,
touched,
errors,
error,
handleChange,
handleSubmit,
handleBlur,
handleReset,
isSubmitting
}) => (
<form onSubmit={handleSubmit}>
<div className="basic-grey">
<input
type="text"
name="firstname"
value={values.firstname}
onChange={handleChange}
onBlur={handleBlur}
placeholder="firstname"
/>
{errors.firstname && <div className="error-msg">{errors.firstname}</div>}
<div className="center buttons">
<button
className="button button-reset"
onClick={handleReset}
disabled={isSubmitting}
>
Reset
</button>
<button
className="button button-submit"
type="submit"
disabled={isSubmitting}
>
Submit
</button>
</div>
</div>
</form>
);
export default Formik({
displayName: "validationFAIL",
validationSchema: Yup.object().shape({
firstname: Yup.string().required()
}),
mapPropsToValues: props => ({
firstname: props.firstname || ""
})
})(SimpleForm);
and here is test for component, jest framework, (project is created using create-react-app):
// component/form/index.test.js
import React from "react";
import MyUserForm from "./index.js";
import { shallow, mount, render } from "enzyme";
import { expect } from "chai";
describe("MyUserForm", () => {
describe("validate", () => {
it("validate correctly", () => {
const myUserForm = mount(<MyUserForm />);
expect(myUserForm.state().isSubmitting).to.equal(false); //ok false == false
myUserForm.find("form").simulate("submit");
expect(myUserForm.state().isSubmitting).to.equal(false); //FAIL true == false WHY? :C
});
});
});
Hi, so say my user API had a nested array like this:
{
id: string,
email: string,
pets: [
{ type: string, name: string }
]
}
Is there a way to implement this kind of form, where i'll be able to add 0-many pets?
@jaredpalmer : Thanks for this great library. It's much better than redux-form
.
Btw, I have one question for the following form:
Each state has a name and a bool field named no_cost
. If no_cost
= true, there's no incurring cost.
I know Yup
support conditional validation, but would you pls tell me how to apply it with formik
?
Docs show
setTouched(fields: { [field]: string }) => void
It looks like it takes
setTouched(fields: { [field]: boolean }) => void
, right?
Firstly, this looks like a great library. Well done, and the documentation looks pretty good as well. But...
The description does nothing to help someone understand how the displayName is used or why they'd care to set it. In fact, it doesn't tell me anything I couldn't already infer from the variable name itself. This is a common mistake I find in lots of documentation.
It's optional, so it would be more helpful if you told me why it exists. When would I want to bother setting this value? How is it useful? Why does this option exist? And if I set it, is it's value completely arbitrary, must it match my component's name, or what?
Hello,
I've built a few React and React Native apps, but am still relatively new to the platform. In what cases would Formik be relevant/applicable for React Native projects? I saw in the readme that a lot of React forms are a bit over-the-top and can cause performance issues. By what factor does Formik improve rendering times/[insert tangible performance metric here]? I'm sorry if creating an issue here is an inappropriate medium for asking this question -- but would appreciate any responses. Thanks!
I'm just trying this library and I get the following warning:
proxyConsole.js:56 Warning: LoginForm is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components
Am I doing anything wrong?
import React from 'react';
import { Formik, InjectedFormikProps } from 'formik';
import Yup from 'yup';
interface IValues {
email: string;
password: string;
}
interface ILoginFormProps {
onSubmit(payload: IValues): void;
}
const LoginForm: React.StatelessComponent<
InjectedFormikProps<ILoginFormProps, IValues>
> = ({ values, handleChange, handleSubmit, errors, error, isSubmitting }) =>
<form onSubmit={handleSubmit}>
<input
type="text"
name="email"
value={values.email}
onChange={handleChange}
placeholder="[email protected]"
/>
{errors.email &&
<div>
{errors.email}
</div>}
<input
type="password"
name="password"
value={values.password}
onChange={handleChange}
placeholder="password"
/>
{errors.password &&
<div>
{errors.password}
</div>}
{error &&
error.message &&
<div style={{ color: 'red' }}>
Top Level Error: {error.message}
</div>}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>;
export default Formik<ILoginFormProps, IValues, IValues>({
validationSchema: Yup.object().shape({
email: Yup.string().email().required(),
password: Yup.string().required()
}),
handleSubmit: (payload, { props, setError, setSubmitting }) => {
props.onSubmit(payload);
}
})(LoginForm);
I'm trying to build a validation process where errors don't show up before the first blur for each input (i.e no visible errors when the user is typing for the first time). But I'm not able to fire handleBlur on the blur event.
Example: https://codesandbox.io/s/nZ6nZnvQR
https://medium.com/@steida/why-validation-libraries-suck-b63b5ff70df5
https://medium.com/@steida/the-boring-react-redux-forms-a15ee8a6b52b
https://github.com/este/este/blob/next/pages/forms.js
Feel free to correct me. I can accept I'm wrong anytime.
Current Behavior
Formik validates only during onChange
events
Desired Behavior
As a user of the library, I'd like to be able to configure whether validation runs during onChange
or onBlur
events and their respective imperative functions ( setFieldValue
and setFieldTouched
).
Ideas:
// Single option
export interface FormikConfig<Props, Values, Payload> {
...
/**
* Tells Formik to validate the form on each input's onChange
* event INSTEAD of the onBlur event
*/
validateOnChange?: boolean;
}
// Two options
export interface FormikConfig<Props, Values, Payload> {
...
/**
* Tells Formik to validate the form on each input's onChange
* event. Default is `false`
*/
validateOnChange?: boolean;
/**
* Tells Formik to validate the form on each input's onBlur
* event. Default is `true`
*/
validateOnBlur?: boolean;
}
Here's the gist of how to do it:
handleChange = (e) => {
// do something async
checkIfUsernameIsTakenAlready(e.target.value)
.then(
() => this.props.handleChangeValue('username', e.target.value),
err => this.props.setError({ ...this.props.errors, username: err.message })
)
}
I have an input that is supposed to contain a number. If I set the validation schema for this field to be yup.number().required()
, when I go to edit the field it complains, likely since it is treating the input value as a string. I see from the yup
docs that they have a cast
method, but I'm not sure how to have formik attempt to cast values before/during validation.
Is there something I'm missing? Am I meant to manually specify this cast in mapValuesToPayload
?
Reference: #68,
As user of Formik, I want to know how to test my Formik forms and inputs with popular test frameworks.
mapPropsToValues
mount
and shallow
change
, blur
, and submit
eventssubmitForm()
to test async handleSubmit
'sdata-test-id=".."
attributesFirst of all, great work!
After seeing issue #11 I tried to accomplish what @eonwhite suggested, as in creating a Component that would receive all the values from an array and the handleChangeValue
function.
I couldn't find a way to update just a particular instance of the array, but instead I had to 'recreate' the entire emails
array with the changed value.
Is this the way I'm supposed to be using handleChangeValue
or is it something I'm missing?
const Emails = ({ handleChangeValue, emails }) =>
<div>
{
emails.map((m, i) =>
<input
name={`email${i}`}
value={m}
onChange={(e) => {
const { name, value } = e.currentTarget;
let newEmails = [...emails];
newEmails[i] = value;
handleChangeValue('emails', newEmails)}
}
/>)
}
</div>
The entire sandbox
Thanks!
Is there a way of handling a file input, whenever I try and do it I just get returned a C:/fakepath/...
as the value. Am I missing something how do I access the file data
Hey ๐
I love the work you've done so far! However, all your examples make use of stateless components for the form components that are passed into formik
as Formik({})(FormComponent)
.
How would one go about passing React components with state into formik
? ๐ค
Also, if it's not too much, can you add examples as to how to use the in-built handleChange
method?
EDIT: Whoops, I missed a whole section of the documentation. Maybe you could make it so that your basic example shows how to use a stateless component and otherwise? Or maybe add this at the very top:
// Formik props are available on `this.props`
Is it possible to expose a validate fields/values method that can be run within the hoc? Right now it looks like validation is run on all fields when a value changes or on submit and it would be nice to run it whenever.
If I return a promise from handleSubmit
I'd like setSubmitting(false)
to be called for me. So the example from the doc could be:
handleSubmit: (payload, { props, setError }) => {
return CallMyApi(props.user.id, payload)
.then(
res => {
// do something to show success
// MyToaster.showSuccess({ message: 'Success!' })
},
err => {
setError(err)
// do something to show a rejected api submission
// MyToaster.showError({ message: 'Shit!', error: err })
}
)
},
If the returned Promise
is rejected, you could also consider calling setError(promiseError)
Hello,
I'm using formik in a project that uses preact with preact-compat (preact-cli). I noticed that issue #16 says preact is supported.
It looks like formik is returning <undefined />
(when looking in React devtools).
I've had a look at the example on codesandbox as well look through the current/closed issues but I can't see what I am doing incorrectly ๐.
Here is the code I'm trying to use:
import { h } from 'preact';
import { Formik } from 'formik';
import yup from 'yup';
const Input = ({ id, name, label, type, value, onChange, error }) => (
<div>
<label for={id} style={{ display: 'block' }}>
{label}
</label>
<input
id={id}
name={name}
type={type}
value={value}
onChange={onChange}
/>
{error && (
<div style={{ color: 'red' }}>
{error}
</div>
)}
</div>
);
const PersonalDetailsForm = ({ values, handleChange, handleSubmit, errors }) => (
<form onSubmit={handleSubmit}>
<Input
id="email"
name="email"
label="Email"
type="text"
value={values.email}
onChange={handleChange}
error={errors.email}
/>
<Input
id="firstName"
name="firstName"
label="First name"
type="text"
value={values.firstName}
onChange={handleChange}
error={errors.firstName}
/>
<Input
id="lastName"
name="lastName"
label="Last name"
type="text"
value={values.lastName}
onChange={handleChange}
error={errors.lastName}
/>
<Input
id="addressLine1"
name="addressLine1"
label="Address line 1"
type="text"
value={values.addressLine1}
onChange={handleChange}
error={errors.addressLine1}
/>
<Input
id="addressLine2"
name="addressLine2"
label="Address line 2"
type="text"
value={values.addressLine2}
onChange={handleChange}
error={errors.addressLine2}
/>
<Input
id="addressCity"
name="addressCity"
label="City"
type="text"
value={values.addressCity}
onChange={handleChange}
error={errors.addressCity}
/>
<Input
id="addressState"
name="addressState"
label="County / State"
type="text"
value={values.addressState}
onChange={handleChange}
error={errors.addressState}
/>
<Input
id="addressZip"
name="addressZip"
label="Postcode / Zip"
type="text"
value={values.addressZip}
onChange={handleChange}
error={errors.addressZip}
/>
<Input
id="addressCountry"
name="addressCountry"
label="Country"
type="text"
value={values.addressCountry}
onChange={handleChange}
error={errors.addressCountry}
/>
<button type="submit" style={{ display: 'block' }}>Submit</button>
</form>
);
const formikEnhancer = Formik({
validationSchema: yup.object().shape({
email: yup.string(),
firstName: yup.string(),
lastName: yup.string(),
addressLine1: yup.string(),
addressLine2: yup.string(),
addressCity: yup.string(),
addressState: yup.string(),
addressZip: yup.string(),
addressCountry: yup.string()
}),
mapPropsToValues: props => ({
email: props.email,
firstName: props.firstName,
lastName: props.lastName,
addressLine1: props.addressLine1,
addressLine2: props.addressLine2,
addressCity: props.addressCity,
addressState: props.addressState,
addressZip: props.addressZip,
addressCountry: props.addressCountry
}),
handleSubmit: (payload, { props, setError, setSubmitting }) => {
console.log('submit!');
}
});
export default formikEnhancer(PersonalDetailsForm);
Thank you in advance.
It would be nice to have typescript examples to show how the interfaces and generics are supposed to be used.
As of 0.7.1, Formik will work with React Native, but I believe the TypeScript signatures need to be updated to support TS and React Native.
hi, I have autosuggest component that needs to be part of the form, Formik has no way of knowing it.
So I got another text field that changes via state when auto suggest is selected, but since this Formik aware text field which also required has not been touched, Formik sees as invalid even though the field has value via state triggered by the autosuggest component. Any idea how can I make Formik aware of the field changes via state?
I discovered a Yup method Yup.reach() that would allow (in theory) for independent field-level validation. Formik currently validates against the entire schema. This has pros and cons. Validating the entire schema allows you to build forms with interdependent fields and conditional validations with just Yup schemas, validating against a field (on the deltas) may be faster (depending on how fast reach
actually is). Regardless, Formik would still validate the whole schema on handleSubmit
, so interdependent schemas would still see their day in court. Error messages could get weird though. Hmmm....
Thoughts?
Naive implementation
handleChange = (e: React.ChangeEvent<any>) => {
e.persist()
this.setState(state => ({ ... })
if (validateOnChange) {
Yup.reach(schema, e.target.name).validate({ ... })
.then(
// ... process errors
)
}
}
Hi,
I have a field that is an array of objects that can have many items.
facies: Yup.array()
.required('Please fill the facies modeling table')
.of(
Yup.object().shape({
LowerLimit: Yup.number().required('Please enter a low value.'),
UpperLimit: Yup.number().required('Please enter a upper value.'),
})
),
When i use
// just an example
handleChangeValue('facies[0].LowerLimit', event.currentTarget.value )
to update the LowerLimit of the first item of facies
it creates a new property in values with this name "facies[0][LowerLimit]"
when it should have updated the LowerLimit property of the first element of facies.
I have seen the code of handleChangeValue and this is because
handleChangeValue = (field: string, value: any) => {
const { touched, values } = this.state;
// Set touched and form fields by name
this.setState(state => ({
...state,
values: {
...values as object,
[field]: value, // <--- in here
},
touched: {
...touched as object,
[field]: true, // <--- in here
},
}));
// Validate against schema
validateFormData<Values>({ ...values as any, [field]: value /* <-- in here */}, validationSchema).then(
() => this.setState({ errors: {} }),
(err: any) => this.setState({ errors: yupToFormErrors(err) })
);
};
This can be resolve with something similar like the set method from lodash from the FP package
Am i missing some other way to update values from arrays or deep nested object?
Thanks in advance for the help.
This is kind of an annoying chore, especially as our list of examples grows. We may want to consider moving to a Lerna monorepo just so we can version the examples together much more easily (and keep them in source code).
How to achieve remote submit
with formik? This useful feature from Redux-form
Really cool library you guys came up with! Especially the first class typescript support is something i really appreciate!
Only thing i don't like is the tight coupling between formik and yup. yup has no real localization support (see jquense/yup/issues/71), so it makes it really hard right now to provide custom and translatable error messages.
Also i have to learn yet another DSL language, instead of simply composing functions together.
Would it be possible to provide a custom validation function, so people could use whatever library and approach they prefer? Here an example, close to your handleSubmit
signature
import isEmail from 'validator/lib/isEmail';
handleValidation: (payload, { props, setErrors }) => {
let errors = {};
if (!isEmail(payload.email)) {
// Hey, now i can have custom error messages!
errors.email = `${payload.email} is no valid email address!`
}
return setErrors(errors);
}
Maybe useful for #51 too!
Hi
I have a dropdown select where selecting one of its values changes the options for next sibling select. Both of the selects also have required validations. Not sure if there is a Formik way internally managing via its callbacks like handleChange or handleChangeValue?
Thanks
I really enjoy this library. Yup works great and I haven't experienced any performance issues validating the entire form when an individual field changes. I did experience an interesting side effect of validating the entire form on field change: setErrors
. Let's say my backend returns {username: 'already taken', field1: 'other error', field2: 'another'}
. I use setErrors
to add those to the individual fields, but when someone changes the username then all of the errors clear because there is no definitions for them in yup, as they were returned in the response. The result is a loss of error visibility.
For now, I'm just going to collect these errors and present them in one giant error box at the top of the form using setError
.
At the moment, if I want to pass my form values to a container, I can do this:
const SubmitForm = ({ handleSubmit ... ) => <form onSubmit={handleSubmit}>...</form>
const enhancer = Formik({
...
handleSubmit (form, {props}) {
props.onSubmit(form)
}
})
export default enhacner(SubmitForm)
Just wondering if it might make sense to support something like this,
const SubmitForm = ({ validateAll, onSubmit... ) => <form onSubmit={() => {
validateAll(onSubmit) // validates form and calls onSubmit only if form is valid
}}>...</form>
const enhancer = Formik({
...
})
export default enhacner(SubmitForm)
In my opinion, this approach is more readable as the logic is located closer to the form (lexically),
I have been unable to get this to work. I'm importing Formik and exporting it as a HOC to my form component. Am I doing something wrong?
I get the following error:
Error
client.bundle.js:18089 Uncaught TypeError: (0 , _formik2.default) is not a function
at Object.defineProperty.value (client.bundle.js:18089)
at __webpack_require__ (client.bundle.js:20)
at Object.defineProperty.value (client.bundle.js:18390)
at __webpack_require__ (client.bundle.js:20)
at Object.<anonymous> (client.bundle.js:16873)
at __webpack_require__ (client.bundle.js:20)
at Object.defineProperty.value (client.bundle.js:19112)
at __webpack_require__ (client.bundle.js:20)
at validateFormat (client.bundle.js:66)
at client.bundle.js:69
Form.js
import React, { Component } from 'react';
import Formik from 'formik';
import Yup from 'yup';
import Grid from 'client/components/shared/grid';
import Form from 'client/components/shared/form';
class DonationForm extends Component {
render() {
const { values = {} } = this.props;
return (
<form>
<Grid width="50" mobile="100">
<Form.Input
label="First Name"
value={values.first_name}
/>
</Grid>
<Grid width="50" mobile="100">
<Form.Input
label="Last Name"
value={values.last_name}
/>
</Grid>
<Grid width="50" mobile="100">
<Form.Input
label="Email Address"
value={values.email_address}
/>
</Grid>
<Grid width="50" mobile="100">
<Form.Input
label="Phone Number"
value={values.phone_number}
/>
</Grid>
</form>
);
}
}
const validationSchema = Yup.object().shape({
first_name: Yup.string().required(),
last_name: Yup.string().required(),
email_address: Yup.string().email().required(),
phone_number: Yup.string().required()
});
export default Formik({ validationSchema })(DonationForm);
Formik is written in TS (great), but your only validation option is yup
, which has no typings in the main repo and there is no externally provided @types/yup
package either.
Makes it difficult to try and adopt Formik while staying purely TS.
I'm sorry if I'm missing something, but is there a reason that handleChangeValue
, unlike handleChange
, sets touched
to true
for the field? https://github.com/jaredpalmer/formik/blob/master/src/formik.tsx#L281
It seems like this "breaks" the case where you do not want to display an error until the input is blurred. https://codesandbox.io/s/v2mM8JrYn
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.