When I set my formvalues using initialValues, I want the normalization and async validation to run. I even tried dispatching both the blur and change action, but both don't work:
dispatch(blur('userdata', 'user_zipcode', '3021LC'));
dispatch(change('userdata', 'user_zipcode', '3021LC'));
What would be the right way to solve this problem?
As for normalizing, it's a little strange that you are initializing with non-normalized data. I would recommend reviewing the Value Lifecycle and perhaps using a combination of a parse and format functions.
As for running async validation, again it's odd that you might be initializing with invalid data, but there is a this.props.asyncValidate() function that you can call in your form component to trigger the async validation.
Does that help?
I'm having this same problem while using initialValues and not getting them normalized:
Using format instead of normalize seems to fix the problem but
format doesn't actually change the data you have on your store like the normalize does so, if you want to do that, then using both may be the best way to fix this? I'm not sure...
So, here's an example:
<Field component={MyCustomInputField} name="phone" format={normalizePhone} normalize={normalizePhone} label="Phone" type="tel" />
format is the first thing on the Value Lifecycle Hooks
Hope this helps!
Related
I've started noticing in console log, multiple warnings for Formik fields where the data is null. see below..
Warning: A component is changing a controlled input of type text to be uncontrolled.
Input elements should not switch from controlled to uncontrolled (or vice versa).
Decide between using a controlled or uncontrolled input element for the lifetime of the component.
The reason data being null is due to the fact that these fields in the database are nullable and are optional in the front-end. I've seen a few suggestions on Stackoverflow where people put ternary operator ?:"" but doing so results in user input being overwritten each time when user moves on to the next field on the form.
e.g.
<Field
component={TextField}
label="Payment Method"
name="paymentMethod"
value={props.initialValues.paymentMethod?
props.initialValues.paymentMethod : ""}
disabled
fullWidth={true}
/>
For now the only workaround is in my API which interacts with MySQL DB. I use IFNULL() and return an empty string or 0 for null fields but I really don't like this approach.
IFNULL(pmethod.payment_method_name, '') as paymentMethod,
Any idea or suggestions on how to handle this?
In Formik, it has props values. If props you are using in value is props of Formik, you can using props.values and nullish coalescing operator like this:
value={props.values.paymentMethod ?? ""}
Thanks Viet for your tip. I ended up using it in a different way. I am setting empty string values to the formik initialValues based on my API response. so, basically I use the coalescing operator on values returned by my API which populates my initialValues for Formik and this has resolved the issue. Also, now it makes sense as to why React throws warnings as it can't determine null or undefined values to re-render them.
I understand the concept of the Controlled component however when I think about it deeply why do we actually need it if we are using onChange method.because everytime we make some change the value of that change will be in the state so there will be a one source of truth either way. why do we need value for making it a controlled component?
<input
name="username"
onChange={this.onChange}
value={this.state.username}
type='text'
placeholder="Full Name"
/>
Because if you don't set the value on the <input> element:
value={this.state.username}
Then when the state is updated and the component re-renders it won't display a value in the UI. Regardless of the state tracked by React, ultimately the UI needs to render as plain HTML. And you need to tell that HTML what the value for that <input> is so it displays (and can be further modified).
well, let's think about it.
if it is a controlled component, it means that you can do whatever you want from the input on the onChange function right? well, now think that you are for some reason transforming the input from the user, lets think about a function that changes numbers:
onChange(event){
const inputValue = event.target.value;
const result = '$' + inputValue + '.00';
this.setState({ value});
}
right? well, basically, this tell us how we changed our state value but how does the input know about these change and the real value we want to show? how does the input know that if the user puts something it should show something else?
12 ---> $12.00
when you control an field, you need to handle the output and the input of these field, because you need to provide everything in order to properly show the data.
if you are not doing any weird magic, maybe you don't need a controlled input.
The pattern of separating out 'what happened' from 'what this does to my app' flows directly from React's use of a declarative style of programming (in comparison to imperative - see this post if you're not familiar with the distinction).
It takes a bit of getting used to when you first encounter it but as your code increases in complexity it makes more and more sense as it keeps things de-coupled and makes it easy to reason about. Changes start as events, which update the state, which is then reflected in your app. It's a loop rather than a 2-way binding.
I'm getting my inputs dynamically from an API call based on a change in select input, but when I try to add to the initial values of Formik, it always gives me an error ...
Warning: A component is changing an uncontrolled input of type text to be controlled.
And it doesn't help if I set enableReinitialize={true} to Formik.
However, if I generated the inputs from a local JSON or object, the error goes away.
What am I doing wrong here ...
https://codesandbox.io/s/test-dynamic-inputs-with-formik-xr9qg
The form submits fine though.
Better use enableReinitialize={true}. This is official Formik API.
You can check this issue
If anyone is facing the same issue, I just found the solution ...
You have to set value={field.value || ''} in the input inside the TextInput component or whatever type you're using in order to fix this issue.
I had a complex, dynamic form and also came across this issue. There are a few things that I'd recommend for anyone debugging this issue in the future:
Set value for your Field component--like Ruby does above.
Ensure that your Formik component has a uniquely identifying key.
Track and debug your initialValues and ensure that all fields are accounted for. You shouldn't have to set the field value like Ruby does--so long as your initialValues object accounts for all of the fields. However, my form dynamically changed Field components--and Ruby's solution is the only one that worked.
If your form is not dynamic--I think it might be best to check your initialValues object first before implementing Ruby's solution. Formik should be taking care of those values for you--which is why it's such an awesome tool.
i've checked with enableReinitialize={true}. But its not working as much as expected. so wrote a useEffect like
useEffect(() => {
formik.setFieldValue('query_string', active?.query);
}, [active])
it's worked !
I am working on an basic React CRUD App and I came across a strange issue.
Using Reactstrap Input Component or the bootstrap class="form-control" the input values are undefined onSubmit.
If I leave the elements as a standard html input the values submit just fine?
I cannot figure out why this is happening.
I put together this demo that illustrates the issue.
Code Sandbox Snippet <- Live Demo
On the AddName.js file I have one Input and one input on submit you can see that the first name submits but the description does not.
<FormGroup>
<input
placeholder="First Name"
ref={nameInput => (this.nameInput = nameInput)}
/>
</FormGroup>
<FormGroup>
<Input
placeholder="Description"
ref={descriptionInput => (this.descriptionInput = descriptionInput)}
/>
</FormGroup>
Can anyone explain why this is happening? Is it possible how I have the refs on the inputs?
Before utilizing 3rd party packages, you should read into using Controlled Components strictly through React. Then, once you understand the flow, incorporate the packages.
I've rewritten your project to include all of the above, as well as written notes describing what I changed and why. There are also a few tricks and shortcuts I've used to simplify the code, such as: setState callback, ES6 Object Deconstruction and Fat Arrow Functions.
Working example: https://codesandbox.io/s/l9m0vor4wq
You should only need to use refs for obtaining a DOM element or a class instance for UI manipulation, instead of obtaining a data value. For example, utilizing a ref to draw attention to a DOM element via using its focus() method or removing attention from it via its blur() method. In your case, we would only use the synthetic event instead of a ref.
On a side note, be careful about using the name as a key in <PersonCard/>, because multiple users can share the same name value. This will cause React to complain that two keys are the same, and cause issues if you ever try to remove, resort, or filter the names list. To keep it simple, I instead used the key provided by the map function. While this approach works, it's not the best solution. Ideally, each person should have an id property with a UUID. This ensures all of your keys will be unique.
Some material-ui components have errorText as a prop which we can use to show errors, But, doing that in react become lot complex if my form has large number of field components.
Please suggest the best way to handle client-side validation with material-ui comonents.
I think your issue is that you have to manage a lot with state/store. In react validation is complex because of one-way binding.
This library https://github.com/vishalvisd/react-validator is one which I found that supports material-ui component validation. Though in general you may use this to validate any component.
I would suggest using some HoC (Higher-order Component) approach. I tested many solutions for form validation in React JS, the one that I always choose is: react-validation-mixin. Take a look at this example.
Example of the standard input:
<input
type='text'
placeholder='Username'
value={this.props.username}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
/>
In this example value of that input comes from props (example with Flux implementation) and that's probably what you aim for too (lots of inputs).
onChange will need to handle value change so that this.props.username gets updated too and onBlur will trigger validation check (so that the error will show up once user leaves the input).
In order to get the error message, use: this.props.getValidationMessages('username')
It's a universal solution and you can use it in different libs. But taking TextField from material-ui, as you asked:
<TextField
floatingLabelText="Username"
value={this.props.username}
errorText={this.props.getValidationMessages('username')}
onChange={this.onChange('username')}
onBlur={this.props.handleValidation('username')}
...
/>
Remember to use HoC with your component: export default validation(strategy)(UserLogin) That way, you will get all the necessary helper methods in props.
If you are using Redux in React project, redux-form give you a simple way to implement form validation.
Check this out: http://redux-form.com/6.4.3/examples/syncValidation/