Clear a field's value on input clear in react-final-form - reactjs

I'm using a custom component with react-final-form. On input change it sets the value to the address field. But when the input is cleared it doesn't update the value of the field. So I'm trying to do it with form mutators.
I have already added a mutator for clearing the field:
mutators={{
clear: ([address], state, { changeValue }) => {
changeValue(state, "address", () => undefined);
}
}}
I tried to add it to my custom onChange function, but it doesn't work.
onChange={event =>
props.input.onChange !== undefined
? props.input.onChange({ value: event })
: form.mutators.clear
}
Or maybe this can be done without mutators at all? I would really appreciate your help. Here is a live example (clearing the field works only on the button click as onClick={form.mutators.clear}).

You can just call form.change('address', undefined) at any time that you'd like to clear the value.

All the default callback are handle by the component. If you want to do a clear with a button click, you can create a custom component and use native callback methods do your thing.
onChange = (event) => {
this.setState({
address:event.target.value
});
}
onClear = () => {
this.setState({
address:''
});
}
<div>
<Field name="address">
<div>
<input
value={this.state.address}
onChange={this.onChange}
/>
</div>
</Field>
<button onClick={this.onClear}>Clear</button>
</div>

The problem is not with the react-final-form in your code, it is due to the react-da data, I have played a lot around your code within 1 day, and checked reset is working with fine with the react-final-form
Just update your render with this code and see reset is working absolutely fine. Yeah! the problem is with react da data. I am not sure about what it does due to less official information for this package.
<div className="App">
<h2>Dadata test</h2>
<Form
mutators={{
clear: ([address], state, { changeValue }) => {
changeValue(state, "address", () => undefined);
}
}}
onSubmit={onSubmit}
render={({ form, handleSubmit, pristine, invalid, values, errors }) => (
<form onSubmit={handleSubmit} noValidate>
<Field name="address" component="input" />
{/* {props => (
<div>
<ReactDadata
token="d19c6d0b94e64b21d8168f9659f64f7b8c1acd1f"
onChange={event =>
props.input.onChange !== undefined
? props.input.onChange({ value: event })
: form.mutators.clear
}
/>
</div>
)}
</Field> */}
<button type="submit" disabled={invalid}>
Submit
</button>
<button type="button" onClick={form.reset}>
Clear
</button>
<Fields names={["address"]}>
{fieldsState => (
<pre>{JSON.stringify(fieldsState, undefined, 2)}</pre>
)}
</Fields>
</form>
)}
/>
</div>
Hope it will help you to resolve the problem.

Related

handleSubmit from formik is invoked whichever button I click

I want to implement a checking form for validity into the project for ordering food using formik but I have encountered some problems creating two buttons. Whichever button is clicked the handleSubmit is invoked. what can I do to solve this problem?
Function goBack only sets the state to false.
export default function Checkout(props) {
function handleSubmit(event) {
// event.preventDefault();
console.log("Hello");
}
return (
<Formik
initialValues={{ userName: "Hi", street: "", postalCode: "", city: "" }}
onSubmit={handleSubmit}
>
{(props) => (
<Form className={styles["form"]}>
<div className={styles["form-control"]}>
<div className={styles["form-control__input"]}>
<label htmlFor="userName">Your name</label>
<Field type="text" name="userName" id="userName"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="street">Street</label>
<Field type="text" name="street" id="street"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="postalCode">Postal code</label>
<Field type="text" name="postalCode" id="postalCode"></Field>
</div>
<div className={styles["form-control__input"]}>
<label htmlFor="city">City</label>
<Field type="text" name="city" id="city"></Field>
</div>
</div>
<div className={styles["form-actions"]}>
<CloseButton type="button" onClick={props.goBack}>Back</CloseButton>
<OrderButton type="submit">Confirm</OrderButton>
</div>
</Form>
)}
</Formik>
);
}
export default function CloseButton(props) {
return <button type={props.type} onClick={props.onClick} className={styles["close-button"]}>{props.children}</button>;
}
export default function OrderButton(props) {
return <button type={props.type} onClick={props.onClick} className={styles['order-button']}>{props.children}</button>
}
I wanted CloseButton to close the form and go back to the list of orders, but it only invokes handleSubmit created by Formik component instead of the function in the props. I have read the documentation but there is neither anything about creating formik with two buttons nor anything related to my problem.
Looks like in props.goBack you meant to reference the props for the component, but instead the props from within Formik are being used (as that is the closest block declaration of props). Since goBack is not defined on the Formik props, you're passing undefined as the onClick handler to the button.
The most straightforward way to fix this is to rename one of the props variables—I'd suggest naming the Formik ones to formikProps or something similar.
A better approach, in my opinion, would be to destructure the props (in both cases, though only one is necessary), like this:
export default function Checkout({ goBack }) {
// ...
return (
<Formik>
{(props) => (
// ...
<CloseButton type="button" onClick={goBack}>Back</CloseButton>
// ...
)}
</Formik>
)
}

How to fix Type Props Error when onChange Event in Formik/Field Input

When I want to trigger the onChange event of Formik/Field(input).
I don't know how to trigger the onChange Event in Formik/Field. So I tried to trigger onChange event in Formik/Form and get the id of event params. But it is facing the problem of Props in Typescript.
Please check my code snippet and let me know how to fix this problem. Thanks in advance.
const InputCustomerForm = () => {
...
const handleFormChange = (event: FormEvent) => {
if (event.target.id === "mobileNumber"){
const value = phoneConvertor(event.target.value);
setUpdatedPhoneNumber(value);
}
}
return (
<OrderPaymentFormContainer className={`${showAccount === true ? 'show' : 'hidden'}`}>
<Formik
initialValues={initialValues}
enableReinitialize={true}
validationSchema={OrderPaymentFormSchema}
onSubmit={(values, actions) => {
handleSendEmail(values);
actions.setSubmitting(false);
}}
>{
({ handleSubmit, errors, touched, isValid }) => (
<Form onSubmit={handleSubmit} onChange={handleFormChange}>
...
<div>
<label>
Mobile Phone Number
</label>
<div>
<div>
<Field id="countryCode" name="countryCode" as="select">
<option defaultValue="1">US</option>
</Field>
</div>
<div>
<Field id="mobileNumber" name="mobileNumber" placeholder="(201) 555-0123" value={updatedPhoneNumber}/>
</div>
</div>
{errors.mobileNumber && touched.mobileNumber ?
(<div className="order-detail--card-form-item-error">{errors.mobileNumber}</div>) : null
}
</div>
...
</Form>
)
}
</Formik>
</OrderPaymentFormContainer>
)
}
export default InputCustomerForm;
As we can see, I hope to get the changed value of input and want to do some function with changed values and return to Input's current value. But it's not working now. Please let me know the problem how to resolve this problem. Thanks
I tried it by manually using pure function but it's not working.
I hope to resolve this problem in typescript.

In React with Formik how can I build a search bar that will detect input value to render the buttons?

New to Formik and React I've built a search component that I'm having issues with the passing of the input value and rendering the buttons based on input length.
Given the component:
const SearchForm = ({ index, store }) => {
const [input, setInput] = useState('')
const [disable, setDisable] = useState(true)
const [query, setQuery] = useState(null)
const results = useLunr(query, index, store)
const renderResult = results.length > 0 || query !== null ? true : false
useEffect(() => {
if (input.length >= 3) setDisable(false)
console.log('input detected', input)
}, [input])
const onReset = e => {
setInput('')
setDisable(true)
}
return (
<>
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
setDisable(true)
setQuery(values.query)
setSubmitting(false)
}}
>
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
</div>
<div className="row">
<div className="col-12">
<div className="text-right">
<button type="submit" className="btn btn-primary mr-1" disabled={disable}>
Submit
</button>
<button
type="reset"
className="btn btn-primary"
value="Reset"
disabled={disable}
onClick={onReset}
>
<IoClose />
</button>
</div>
</div>
</div>
</Form>
</Formik>
{renderResult && <SearchResults query={query} posts={results} />}
</>
)
}
I've isolated where my issue is but having difficulty trying to resolve:
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
From within the Field's onChange and value are my problem. If I have everything as posted on submit the passed query doesn't exist. If I remove both and hard code a true for the submit button my query works.
Research
Custom change handlers with inputs inside Formik
Issue with values Formik
Why is OnChange not working when used in Formik?
In Formik how can I build a search bar that will detect input value to render the buttons?
You need to tap into the props that are available as part of the Formik component. Their docs show a simple example that is similar to what you'll need:
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
otherStuff()
}}
>
{formikProps => (
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
name="query"
onChange={formikProps.handleChange}
value={formikProps.values.query}
/>
</div>
<button
type="submit"
disabled={!formikProps.values.query}
>
Submit
</button>
<button
type="reset"
disabled={!formikProps.values.query}
onClick={formikProps.resetForm}
>
</Form>
{/* ... more stuff ... */}
)}
</Formik>
You use this render props pattern to pull formiks props out (I usually call them formikProps, but you can call them anything you want), which then has access to everything you need. Rather than having your input, setInput, disable, and setDisable variables, you can just reference what is in your formikProps. For example, if you want to disable the submit button, you can just say disable={!formikProps.values.query}, meaning if the query value in the form is an empty string, you can't submit the form.
As far as onChange, as long as you give a field the correct name as it corresponds to the property in your initialValues object, formikProps.handleChange will know how to properly update that value for you. Use formikProps.values.whatever for the value of the field, an your component will read those updates automatically. The combo of name, value, and onChange, all handled through formikProps, makes form handing easy.
Formik has tons of very useful prebuilt functionality to handle this for you. I recommend hanging out on their docs site and you'll see how little of your own code you have to write to handle these common form behaviors.

Input loses focus when using custom input for Formik Field in FieldArray

I am using custom input components to handle my form data, and noticed strange behaviour. Only when I am using FieldArray with custom input components the input loses focus as I type.
Here is the form setup:
<Formik
enableReinitialize
initialValues={{ ...getInitialState() }}
onSubmit={(values, actions) => {
save(values, actions)
}}
validationSchema={schema}
>
{({ values, isSubmitting, setFieldValue, dirty }) => (
...
<Images />
...
)}
</Formik>
And inside my Images component
import { imageState } from "states"
import Input from "form/input"
function Images() {
...
return (
<div className={styles.wrapper}>
<FieldArray
name="images.posters"
render={({ form, push, remove }) => {
const images = form.values.images.poster
return (
<>
<button onClick={() => push(imageState)}>Add Poster</button>
{images.map((image, index) => (
<div key={index} className={styles.imageGroup}>
<Field //using custom input loses focus
name={`images.poster.${index}.src`}
component={Input}
/>
<Field //using Formik default component doesn't loose focus
name={`images.poster.${index}.src`}
/>
<button onClick={() => remove(index)}>Remove Poster</button>
</div>
))}
</>
)}}
/>
</div>
)
}
Is there another way I have to use custom inputs for FieldArray? I do not experience this problem when I am not using FieldArray.

ReactJS: OnChange handler auto submitting data before onClick

I'm still relatively new to React/Javascript & working with its functions. I created a component that takes user input and renders a button that allows a user to link to an outside URL.
The button title is created by the user and then the URL is added.
However, when a url is pasted or I begin typing it, the onChange handler automatically creates the button without using the onSubmit function. So if I begin typing a paste a url (even if the data is wrong), the onChange event takes whatever I've input without allowing me to click "submit first".
I'm following this tutorial as a guideline for creating my onChange/onSubmit functions: https://www.youtube.com/watch?v=qH4pJISKeoI&t=304s. His demo does not have the same issue and his input fields solve a different problem.
onChange & onSubmit Functions
this.state = {
links: [],
url: '',
title: ''
}
}
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault(e)
}
...
render() {
if (this.state.url === '') {
return (
<>
<form>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placholder="your-link.com"
onClick={(e) => { e.stopPropagation() }}
disabled={this.state.title === ''}
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button onClick={this.onSubmit}>Submit</button>
</>
)
} else {
return (
<>
<div>
<p>{this.state.title}</p>
</div >
</>
)
}
}
}
I've tried separating the onChange events using onChange={this.title} and {this.url} , disabling the URL field until the title is added, and adding onClick={(e) => { e.stopPropagation() }} in the url input field to prevent autosubmission as shown in the code above.
Any help understanding what causes this problem would be appreciated.
Let's check what is happening:
We have onChange on input with url.
When anything is being changed in this input field,
On change is called and it triggers render method.
In render if (this.state.url === '') { this is no longer true so it creates link without needing to submit.
Prevent default will not work while you have params in it:
e.preventDefault(e)
// probably this may be a typo instead?
// it's preventing you to go further line due to error.
Remove e param and it should be fine:
e.preventDefault()
<form onSubmit={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.onChange(e)}
/>
<input
name="url"
type="url"
placholder="your-link.com"
disabled={this.state.title === ''}
onChange={e => this.onChange(e)}
/>
<br />
<button type="submit">Submit</button>
</form>
do changes like this and check

Resources