Formik Fetch API Values Undefined on submit - reactjs

I am new to react and I need help with submitting my form with values that was obtained from an API.
When the form is loaded, the user has to input an ID in order for it to load the remaining field and values from the API. Once the User has inserted an ID value, the user can then click on submit and the in the back end it should POST the results capture in the Console log. Currently on submit input values are Undefined.
Visit CodeSandbox link below for a working example of this
Code: https://codesandbox.io/s/formik-fetch-post-3remet
Alternatively, here is my Code:
import React, { useState, useEffect } from "react";
import "./styles.css";
import { Box, Button, TextField } from "#mui/material";
import { Formik, Form } from "formik";
export default function App() {
const [datas, setdatas] = useState([]);
const [searchId, setSearchId] = useState("");
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/users/?id=${searchId}`)
.then((Response) => Response.json())
.then((datas) => setdatas(datas));
}, [searchId]);
const handleCange = (e) => {
setSearchId(e.target.value);
};
return (
<Formik
initialValues={{ name: datas.name }}
enableReinitialize={true}
onSubmit={(data, { resetForm }) => {
console.log(data);
resetForm();
}}
>
<div className="App">
<h1>Search User(enter a value between 1-5)</h1>
<div className="searchBox">
<input
type="text"
placeholder="Enter user ID"
onChange={(e) => handleCange(e)}
/>
</div>
<div className="itemsSec">
{datas.map((datas) => (
<div key={datas.id} className="items">
<Form>
<Box>
<TextField
className="field"
label="name"
name="name"
type="text"
id="name"
variant="filled"
value={datas.name}
onBlur={Formik.handleBlur}
onChange={Formik.handleChange}
sx={{ gridColumn: "span 2" }}
key={datas.id}
>
{" "}
value={datas.name}
</TextField>
</Box>
<Button type="submit" color="secondary" variant="contained">
Submit
</Button>
</Form>
</div>
))}
</div>
</div>
</Formik>
);
}

Related

How to submit Formik when button submit outside tag formik in ReactJs?

I have a component composition as above, the box with brown color is the parent and has a blue child box as the formix container and the right side with the green color is the container where the button is placed. is it possible to submit a form with a button outside the formix tag?
I read the documentation but still not found the solution.
you can handle it using the Formik tag innerRef reference. I added a working demo pls find here.
import React, { useRef } from "react";
import { render } from "react-dom";
import { Formik } from "formik";
import * as Yup from "yup";
import "./helper.css";
const App = () => {
const formRef = useRef();
const handleSubmit = () => {
if (formRef.current) {
formRef.current.handleSubmit();
}
};
return (
<div className="app">
<Formik
innerRef={formRef}
initialValues={{ email: "" }}
onSubmit={async (values) => {
await new Promise((resolve) => setTimeout(resolve, 500));
alert(JSON.stringify(values, null, 2));
}}
validationSchema={Yup.object().shape({
email: Yup.string().email().required("Required")
})}
>
{(props) => {
const {
values,
touched,
errors,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email" style={{ display: "block" }}>
Email
</label>
<input
id="email"
placeholder="Enter your email"
type="text"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.email && touched.email
? "text-input error"
: "text-input"
}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
</form>
);
}}
</Formik>
<button type="submit" onClick={handleSubmit}>
Submit
</button>
</div>
);
};
render(<App />, document.getElementById("root"));

Reset a Formik form after clicking another Formik form

I have a react.js component which is a facet and its content is populated according to some keyword search. Every time that a new search is made, the content of the facet changes (country name - number). The facet and the search are two different Formik forms. In this example, if any of the country is checked then it is kept in the next search if the same country is also found in the following search. How is it possible to clear the facet form after every keyword search?
import React, { useState, useEffect } from 'react';
import { Formik, Field, FieldArray, Form, useFormikContext } from 'formik';
function Facet (props) {
return(
<div>
<Formik
enableReintialize={true}
initialValues={{
countries: ''
}}
onSubmit={async (values) => {
await sleep(500);
alert(JSON.stringify(values, null, 2));
}}
>
{({ values }) => (
<Form>
<FormObserver />
<b>Countries </b>
<div>
<FieldArray
name="countries"
render={arrayHelpers => (
<div>
{props.countryDist.map(countries_dist => (
<div key={countries_dist.country}>
<label>
<input
name="countries"
type="checkbox"
value={countries_dist.country}
checked={values.countries.includes(countries_dist.country)}
onChange={e => {
if (e.target.checked) {
arrayHelpers.push(countries_dist.country);
} else {
const idx = values.countries.indexOf(countries_dist.country);
arrayHelpers.remove(idx);
}
}}
/>
{" " + countries_dist.country +
" (" + countries_dist.count + ")"}
</label>
</div>
))}
</div>
)}
/>
</div>
</Form>
)}
</Formik>
</div>
);
}
export default Facet;
Edit:
Search.js
import React from 'react';
import { Formik } from 'formik';
import { Button, Col, Form, Row } from 'react-bootstrap';
function Search (props) {
const onSubmit_func = async (values, actions) => {
await props.search_p(values.query);
}
return (
<Formik
initialValues={{
query: ''
}}
onSubmit={onSubmit_func}
>
{({
handleChange,
handleSubmit,
setFieldValue,
values
}) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group controlId='query'>
<Row>
<Col>
<Form.Control
autoFocus
type='text'
name='query'
value={values.query}
onChange={e => {
setFieldValue('countries', [])
handleChange(e)
}}
/>
</Col>
<Col>
<p>
<Button type='submit' variant='primary'>Search</Button>
</p>
</Col>
</Row>
</Form.Group>
</Form>
)}
</Formik>
);
}
export default Search;
As I understand you expect that on every change of props.countryDist (populated according to some keyword search) checked countries will resetted.
I suggest to use setFieldValue as a method to reset countries on change of search keyword in search component:
setFieldValue('countries', [])

React Formik onSubmit Async called twice

I am trying to use async with onSubmit with following code for Formik in React
import React from "react";
import { Formik, Form, Field } from "formik";
import { Row, Col, Button } from "react-bootstrap";
const AddUser = () => {
const initialValues = {
name: "",
};
return (
<>
<Row className="h-100">
<Col xs={12} sm={1}></Col>
<Col xs={12} sm={10} className="align-self-center">
<div className="block-header px-3 py-2">Add Dataset</div>
<div className="dashboard-block dashboard-dark">
<Formik
initialValues={initialValues}
onSubmit={async (values, { setSubmitting }) => {
alert("hi");
setSubmitting(false);
}}
>
{({ isValid, submitForm, isSubmitting, values }) => {
return (
<Form>
<Field
name="name"
label="Name"
placeholder="Dataset Name"
/>
<Button
type="submit"
disabled={!isValid || isSubmitting}
className="w-100 btn btn-success"
onClick={submitForm}
>
Add Dataset
</Button>
</Form>
);
}}
</Formik>
</div>
</Col>
<Col xs={12} sm={1}></Col>
</Row>
</>
);
};
export default AddUser;
When I try to submit. It does alert 'hi' twice. When I don't use onSubmit as async then it works fine.
What am I doing wrong or is there any other way to perform async functionalities as I need to perform RestAPI calls?
Delete type="submit", because there is already an action onClick={submitForm}
<Button
type="submit"
disabled={!isValid || isSubmitting}
className="w-100 btn btn-success"
onClick={submitForm}
>
Be sure to NOT add both
onClick={formik.formik.handleSubmit}
and
<form onSubmit={formik.handleSubmit}>.
Should be one or the other.
I faced the same issue. Adding e.preventDefault() in my Form Submit Handler worked
for me.
onSubmitHandler = (e) => {
e.preventDefault();
//Handle submission
}

React - Material-UI - How to use Select with multiple values inside react-hook-form

I am trying to use UI-Material Select with multiple options inside react-hook-form without success.
I had this working before trying to do it with multiple options
<form onSubmit={handleSubmit(onSubmit)}>
<Row className="mb-2">
<Col sm={6}>
<FormControl className="select-language">
<InputLabel> {t('Languages')}</InputLabel>
<Controller
as={
<Select>
{Config.languages.map(m => <MenuItem key={m.code} value={m.text}> {t(m.text)} </MenuItem>)}
</Select>
}
defaultValue={user.language}
name="language"
control={control}
>
</Controller>
</FormControl>
</Col>
</Row>
</form>
I tried to add multiple to the Select element which lead me to another error.
I tried also to keep only the Select element without the Controller wrapper, but then I can't get the language value in onSubmit
Very simple codeSandBox that shows that I can't get value from Select when submitting the form: https://codesandbox.io/s/react-hook-form-example-s7h5p?file=/src/index.js
I would appreciate any help
Thanks
If anyone looking for a easy solution, this might come in handy. Multiple select options become very easy now with Select Component. If you look at the Select component, you just have to set the default value to an array and pass the "multiple" prop.
import {
Button,
FormControl,
InputLabel,
MenuItem,
Select
} from "#mui/material";
import { Controller, useForm } from "react-hook-form";
const FCWidth = {
width: "20rem"
};
export default function App() {
const { control, handleSubmit } = useForm();
const formSubmitHandler = (formData) => {
console.log(formData);
};
const ages = ["10", "20", "30"];
return (
<div className="App">
<form onSubmit={handleSubmit(formSubmitHandler)}>
<Controller
name="age"
control={control}
type="text"
defaultValue={[]}
render={({ field }) => (
<FormControl sx={FCWidth}>
<InputLabel id="age">Age</InputLabel>
<Select
{...field}
labelId="age"
label="age"
multiple
defaultValue={[]}
>
{ages.map((age) => (
<MenuItem value={age} key={age}>
{age}
</MenuItem>
))}
</Select>
</FormControl>
)}
/>
<FormControl sx={FCWidth}>
<Button
type="submit"
variant="contained"
fullWidth
sx={{ marginTop: ".75rem", fontWeight: "bold" }}
>
Submit
</Button>
</FormControl>
</form>
</div>
);
}
Here is the code sandbox link https://codesandbox.io/s/select-multiple-option-with-mui-and-react-hook-form-2kv2o
I know that this old but someone may need it later, maybe this one would work for you,
just check the render Controller props
import React from "react";
import {
TextField,
ListItemText,
Checkbox,
MenuItem,
makeStyles
} from "#material-ui/core";
import { useForm, Controller } from "react-hook-form";
const useStyles = makeStyles({
root: {
width: "200px"
},
center: {
textAlign: "center"
}
});
export default function SelectTextField() {
const classes = useStyles();
const { handleSubmit, control } = useForm();
const nums = [1, 2, 3, 4];
const onSubmit = (e) => {
console.log(e);
};
return (
<form className={classes.center} onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="selectedNumbers"
defaultValue={[]}
render={({ onChange, value }) => {
console.log(value);
return (
<TextField
classes={{ root: classes.root }}
select
id="Numbers"
variant="outlined"
label="Numbers"
SelectProps={{
multiple: true,
value: value,
renderValue: (selected) => selected.join(", "),
onChange: onChange
}}
>
{nums.map((n) => (
<MenuItem key={n} value={n}>
<Checkbox checked={value.includes(n)} />
<ListItemText primary={n} />
</MenuItem>
))}
</TextField>
);
}}
/>
<div>
<button type="submit">Submit</button>
</div>
</form>
);
}
also, you can and play with it here
https://codesandbox.io/s/multi-select-input-u0cr3?file=/demo.js
also can check this on the docs
https://react-hook-form.com/get-started#ReactNative
First of all, i think your version is on v3, so you may want to upgrade:
https://codesandbox.io/s/react-hook-form-example-5lrij?file=/src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { useForm, Controller } from "react-hook-form";
import { Select, MenuItem } from "#material-ui/core";
import "./styles.css";
const languages = [
{
code: "en-US",
text: "English"
},
{
code: "zu",
text: "Another Language"
}
];
export default function App() {
const { register, handleSubmit, control } = useForm();
const onSubmit = data => console.log(data);
return (
<div className="container">
<div className="col-sm-12">
<h3>Client Profile</h3>
</div>
<div className="col-sm-12">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<input
className="form-control"
type="text"
placeholder="Name"
name="Name"
ref={register}
/>
</div>
<div className="form-group">
<Controller
name="Language"
control={control}
as={
<Select>
{languages.map(m => (
<MenuItem key={m.code} value={m.text}>
{" "}
{m.text}{" "}
</MenuItem>
))}
</Select>
}
defaultValue={languages[0].text}
/>
</div>
<div className="form-group">
<input className="btn btn-primary" type="submit" />
</div>
</form>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
here is the fixed version by using Controller

How to use custom radio component with react-final-form?

I am trying to use a custom Radio component with React-final-form but it is not acting as a radio button but as a checkbox, ie, all the buttons are open for selection.
The 3rd party Radio button has the following schema:
checked boolean
Whether or not radio is checked
onChange () => void
Called when the user attempts to change the checked state
name string
The input name, used to reference the element in JavaScript
I created a custom Component for using the Radio Component:
const CustomRadio = (props: any) => (
<Radio
{...props.input}
{...props.rest}
name={props.name}
onChange={() => props.input.onChange()}
/>
)
and I am using it as follows:
<Field name="food"
component={CustomRadio}
value="1"
/>
<Field name="food"
component={CustomRadio}
value="2"
/>
Being very new to RFF and new to React, I may be doing something very wrong, hence any help will be appreciated.
Basically, I want to use RFF with my 3rd party components. Though I have been successful to use my Input component with RFF as expected, Radio Button is the one creating problems.
Here is the correct implementation for Radio with react-final-form:-
https://codesandbox.io/s/vibrant-easley-5n1ek?file=/index.js
/* eslint-disable jsx-a11y/accessible-emoji */
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import Radio from "#material-ui/core/Radio";
import FormLabel from "#material-ui/core/FormLabel";
const RadioWrapper = (props) => {
const {
input: { checked, value, name, onChange, ...restInput },
} = props;
return (
<Radio
name={name}
inputProps={restInput}
onChange={onChange}
checked={checked}
value={value}
/>
);
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const onSubmit = async (values) => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const App = () => {
return (
<Styles>
<h1>React Final Form - Simple Example</h1>
<a
href="https://final-form.org/react"
target="_blank"
rel="noopener noreferrer"
>
Read Docs
</a>
<Form
onSubmit={onSubmit}
initialValues={{
employed: false,
all_sub_tenants: "true"
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<FormControl component="fieldset">
<FormLabel component="legend">
Select Tenants
</FormLabel>
<RadioGroup aria-label="allSubTenants" name="allSubTenants">
<FormControlLabel
value="true"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"true"}
/>
}
label="All Sub-Tenants"
/>
<FormControlLabel
value="false"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"false"}
/>
}
label="Select Sub-Tenants"
/>
</RadioGroup>
</FormControl>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
</div>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
};
render(<App />, document.getElementById("root"));

Resources