React final form initialValue clears onchange - reactjs

I've been using react-final-form a while, and today i got caught up in a problem.
i want to be able to have a initialValue in a input field, and a checkbox next to it that clears the input field.
But when i run the onChange on the inputfield, that clears the checkbox because i don't wanna be able to let the user a checkbox value or a input value.
I hope someone understands the logic and can give me some hint on how to solve this.
I hav'nt tried mutators because i've never work with that, but if it would solve my case, i will look into it.
<Field
name={input-field}
component={InputField}
initialValue="500-"
/>
<OnChange name="input-field">
{() => {
props.form.change(checkbox, false);
}}
</OnChange>
</div>
<div>
<Field name={checkbox} component={CheckBox} type="checkbox" />
<OnChange name="checkbox">
{() => {
props.form.change(input-field, "");
}}
</OnChange>

Related

React final form - Unable to pass function to oChange prop

I have a in a form using react final form. I'm trying to pass the value of the current input to a function thats used when the field value changes. However when I type, it's taking no input.
<Field name="myField">
{({ input, meta }) => (
<div>
<TextField
type="text"
name={input.name}
value={input.value}
onChange={() =>
handleChange(input.value)
}
label="Title"
/>
</div>
)}
</Field>
I have a function handleChange above the render method. All I want to do is console the current value, and use a setState hook to update a state variable.
function handleChange(item: string) {
setTitle(item);
console.log(item);
}
What am I doing wrong?
I would personally use a useEffect to achieve this, but the issue is that once you add your own useEffect onto it, then it overrides the default action which saves the form value to the form itself.
So first you still have to do the default onChange. And you want to take the value from the input field using e.target.value.
In your example, you are passing the value of the input field into your handeChange, but becuase you arent saving the value back into the input and the form, its always going to be empty.
<Field name="myField">
{({input}) => (
<div>
<TextField
name={input.name}
value={input.value}
onChange={(e, val) => {
console.log(e.target.value);
handleChange(e.target.value)
input.onChange(e.target.value);
}}
/>
</div>
)}
</Field>

How to subscribe to field changes only after the form has been initialized in react-final-form

I have a react-final-form form, which needs to be initialized from the state. When one of the fields changes I want to reset the form to initial (empty) values. So I use subscription to the field's dirty state and if it changes I use OnChange to reset the form:
<Field name="option" subscription={{ dirty: true }}>
{({ input: { onChange } }) => (
<OnChange name="option">
{value => {
form.reset({
...initialValues,
option: value
});
}}
</OnChange>
)}
</Field>
But it doesn't work, as the form gets reset immediately after it has been initialized. Is there any way to separate these two events? So that I could reset the form only if its field has been modified by the user?
Here is the link to my codesandbox.
It doesn't work because <Field /> component will need to be rendered at least first time because its purpose is to rendering field UI not to hook callback. I'd suggest you to use <FormSpy /> instead because it intend for hooking callback even though it might hard for specific field
<FormSpy
subscription={{ dirtyFields: true }}
onChange={props => {
if (props.dirtyFields.option) {
form.reset({
...initialValues,
option:
form.getFieldState("option") &&
form.getFieldState("option").value
});
}
}}
/>
codesandbox
FormSpy

React Formik with a custom component : lifting state up while validating

I am trying to use Formik on my form that successfully does some state lift up from a custom Input child component to its parent (following that tutorial from React's official website)
The following sandbox shows a basic example of what I have so far :
https://codesandbox.io/s/formik-with--or-without-custom-component-d8sof
(yes, there is some styled-components going on with InputStyled but it's supposed to be "transparent")
<Input //switch to input to try other scenario
type="number"
name="surface"
placeholder="please type surface"
onValueChange={handleSurfaceChange}
unit="sq feet"
value={values.surface}
onChange={handleChange}
/>
The excerpt above shows a custom component called Input (please note the capitalized "I")
With this custom component Input : lifting state up works but surface is not tracked by Formik and validation always fails.
With input (lower case - not calling my custom component) : validation by Formik works but I'm not using my custom component therefore I'm not engaging in the lifting of the child state up.
=> My goal would be to make both work.
So I tried using <Field component={Input} /> instead of my <Input />
https://jaredpalmer.com/formik/docs/api/field
But I cannot get my head around how to make the code work.
I started working on another codesanbox example following different trails here and there but things are getting messy.
https://codesandbox.io/s/formik-with--or-without-custom-component-ybbm7
In the parent:
<Field
component={Input} //my custom React Component
type="number"
name="surface"
placeholder="please type surface"
onValueChange={handleSurfaceChange}
value={values.surface}
//at a loss below
//onChange={handleChange}
// handleChange={e => {
// console.log("Entering handleChange in Field...");
// // call the built-in handleChange
// handleChange(e);
// // and do something about e
// let someValue = e.currentTarget.value;
// console.log("someValue = " + someValue);
// }}
/>
In the child (it's a styled-component, nothing fancy,just a regular input "decorated" with CSS) :
<InputStyled
{...field}
{...props}
id={props.name}
name={props.name}
type={props.type}
//value={props.value}
onChange={handleChange}
// onChange={newValue => {
// setFieldValue(field.name, newValue);
// console.log("newValue = " + newValue);
// }}
placeholder={props.placeholder}
/>
{touched[field.name] && errors[field.name] && (
<div className="error">{errors[field.name]}</div>
)}
I cannot find the right way to deal with the onChange, handleChange events from Formik and from myself. the lifting of the state up and the Formik validations are broken.
Can someone point me in the right direction for the correct syntax please ?

Mutator to covert text to uppercase

I tried different ways to implement mutator to convert text to uppercase as soon as user input text in the text field. But was not yet successful. The example provided by Erick seems correct, but maybe I am missing something.
/** Converts a form value to uppercase **/
const upper = ([name], state, { changeValue }) => {
changeValue(state, name, (value) => value.toUpperCase())
}
<Form
onSubmit={onSubmit}
mutators={{
...arrayMutators,
upper
}}
render={({
handleSubmit,
mutators: { push, pop, upper }, // injected from final-form-arrays above
pristine,
reset,
submitting,
values
}) => {
return (
<form onSubmit={handleSubmit}>
<div>
<label>Company</label>
<Field name="company" component="input" onChange={(e) => upper('company')} />
</div>
</form>
)}
}
/>
It's throwing an error when calling toUpperCase on value as value is coming undefined there. Really appreciate any help!
Update: 27-Oct-2018
I have realized we can use parser too, to solve this problem:
upper = value => {
return value ? value.toUpperCase() : ''
}
<Field name="company" component="input" parse={this.upper} />
Still looking for how mutator works and what's the error in my code.
Already Tried:
Mutate state based on existing fields
How to set/change Field value from external user action 🏁 React Final Form
As I know about react-final-form you can get this data directly
I will suggest, you can use this code
onChange={(event, value) => input.onChange(value.toUpperCase())}
https://codesandbox.io/s/0x9y71nwyp

Sync validation on a radiogroup (v6)

How can I display sync-validation errors for my radiogroup when using the v6 version of redux-form? One option would be to create multiple renderField functions, in which only one (the last one) would display the errors. I currently have it setup like this:
const renderField = ({ input, meta: { touched, error } }) => (
<span>
<input
{...input}
/>
{
touched &&
error &&
<div>
{error}
</div>
}
</span>
);
// Form-component
// I loop trough multiple values
<Field
type="radio"
component={renderField}
id={`${field.name}-${value}`}
value={value}
name={field.name}
/>
<Field
type="radio"
id={`${field.name}-${value}`}
value={value}
name={field.name}
/>
In this way, the errors get presented multiple times (for each value). I could pass an extra prop when it is the last value, to enable the errors for just that field. Although that would work, it feels kinda nasty.
This is an interesting question. Another option would be to write a component that was just in charge of rendering errors.
const renderError = ({ meta: { touched, error } }) =>
touched && error && <div>{error}</div>
Then, after you had rendered your radio buttons, you could do a:
<Field name={field.name} component={renderError}/>

Resources