Formik value is undefined - reactjs

Why I can't get the data every time I change the field? can somebody help me to configure this out? did I miss something in my code? I just want that if the user clicks the submit, it will capture what I inputted in TextField and Select
const [ author, setAuthor] = useState('');
const [ datef, setDateF] = useState('');
const [ datet, setDateT] = useState('');
const handleChangeAuthor = (event) => {
console.log("handleChangeAuthor: ", event)
setAuthor(name)
};
const handleChangesetDateF = (event) => {
console.log("handleChangesetDateF: ", event)
setDateF(name)
};
const handleChangesetDateT = (event) => {
console.log("handleChangesetDateT: ", event)
setDateT(name)
};
const handleSubmit= async(valuesToSubmit) =>
{
console.log("valuesToSubmit: ", valuesToSubmit)
}
............
<Formik
initialValues={{
strdatefrom:datef,
strdateto:datet,
intuserauthorid:author,
intfmdocumentclassificationsid:selecteddocClassification,
intlimit:"100",
intoffset:"0"
}}
onSubmit={(values) =>{ console.log("submit"); handleSubmit(values)}}
>
{({ handleChange, handleBlur, handleSubmit, values, errors, isValid,touched,setFieldValue }) => (
<>
<Grid container>
<Grid xs={12} className={classes.grid}>
<TextField
id="date"
label="Date from"
type="date"
name="datet"
onChange={handleChangesetDateF(value.datet)}
defaultValue="2017-05-24"
name="datef"
className={classes.textField}/>
</Grid>
<Grid xs={12} className={classes.grid}>
<TextField
id="date"
label="Date to"
type="date"
name="datef"
onChange={handleChangesetDateT(value.datef)}
defaultValue="2017-05-24"
className={classes.textField}/>
</Grid>
<Grid xs={12} className={classes.grid}>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel htmlFor="outlined-age-native-simple">Author</InputLabel>
<Select
name="author"
value={author}
onChange={handleChangeAuthor(value.author)}
label="Author">
{users}
</Select>
</FormControl>
</Grid>
</>
)}
</Formik>
from this line please ignore this message, I do this message so that i
can submit a question here

You Dont have to use a local state for formik, formik can manage the state internally so you will have to do something like this to update the value.
<TextField
id="date"
label="Date from"
type="date"
name="datet"
onChange={event=>setFieldValue('datet',event.target.value)}
defaultValue="2017-05-24"
name="datef"
className={classes.textField}
value={values.datet}/>
The setFieldValue in formik can update the formik state which you can retrieve in handlesubmit call

Related

Formik Default Values UseEffect

I am trying to prepopulate a Formik with JSON data. The data appears fine and it is returned. I have two issues.
I am using ASP.NET Core as the back end. Should I use values or initialValues as the variable? When I use initialValues, I get assign fields. The labels are still populated.
The labels are still populated, after I send a default value. All the fields are read only and I cannot edit them:
Here is my code:
function OrdersToReporting() {
const [initialValues, setInitialValues] = useState<OrdersToReportingViewModels>({ });
useEffect(() => {
agent.Settings.getOrdersSettings().then((userList) => {
let solutionName = (new URLSearchParams(window.location.search)).get("SolutionName");
let solutionWebsite = (new URLSearchParams(window.location.search)).get("SolutionWebsite");
userList.data.SolutionName = solutionName;
userList.data.SolutionWebsite = solutionWebsite;
setInitialValues(userList.data);
});
}, []);
const handleSubmit = async (
values: any,
{ resetForm, setErrors, setStatus, setSubmitting }: any
) => {
try {
await timeOut(1500);
agent.Settings.saveOrdersSettings(values);
resetForm();
setStatus({ sent: true });
setSubmitting(false);
} catch (error: any) {
setStatus({ sent: false });
setErrors({ submit: error.message });
setSubmitting(false);
}
};
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
touched,
values,
status,
}) => (
{isSubmitting ? (
<Box display="flex" justifyContent="center" my={6}>
<CircularProgress />
</Box>
) : (
<form onSubmit={handleSubmit}>
<Grid container spacing={6}>
<Grid item md={6}>
<TextField
name="SolutionName"
label="Solution Name"
value={initialValues.SolutionName}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
<TextField
name="SolutionWebsite"
label="Solution Website"
value={initialValues.SolutionWebsite}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
<TextField
name="lastDownloadUtc"
label="Last Download Date Start"
value={initialValues.LastDownloadUtc}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
</Grid>
<Grid item md={6}>
<TextField
name="lastDownloadUtcEnd"
label="Last Download Date End"
value={initialValues.LastDownloadUtcEnd}
fullWidth
onBlur={handleBlur}
onChange={handleChange}
variant="outlined"
my={2}
/>
</Grid>
</Grid>
<Button
type="submit"
variant="contained"
color="primary"
mt={3}
>
Save changes
</Button>
</form>
)}
)}
</Formik>
);
}
For your questions,
You should use initialValues to assign default values to your fields.
since you are getting the data from some function, there might be a delay in setting initialValues. So pass enableReinitialize={true} in formik props.
You were not able to change the values because you set
value={initialValues.fieldName} // always value will be this unless you change initialValues state
for every textfield. Always this will be same even if you edit.
Just remove the value property formik will handle it by default.

React input onChange lag (many textfields)

I have quite a large form with many textfields inside, there are about 60-70 textfields inside.
Certainly it begins to lag and I know that the re-rendering could be a problem, also of the reason of having all values in the component state. I have no idea how to split it correctly or how I should solve that.
Main Component -> View
const [values, setValues] = useState({
value1: '',
...
value60: '',
});
return (
<div className={classes.root}>
<form>
<Grid container spacing={2}>
<Grid item xl={12}>
<Breadcrumb breadcrumb={breadcrumb}/>
</Grid>
<BlockInputBasic handleChange={handleChange.bind()} values={values}/>
<BlockInputTarget handleChange={handleChange.bind()} values={values}/>
</Grid>
</form>
</div>
);
Child Component
export default function BlockInputBasic(props) {
return (
<TextField
fullWidth
label="Name"
name="name"
onChange={props.handleChange}
required
value={props.values.name}
variant="outlined"
/>
<TextField
fullWidth
label="Name2"
name="name2"
onChange={props.handleChange}
required
value={props.values.name}
variant="outlined"
/>
....
<TextField
fullWidth
label="Adress60"
name="Adress60"
onChange={props.handleChange}
required
value={props.values.name}
variant="outlined"
/>
);
}
I really appreciate your help!
You could initialise state with same keys as name prop of textfields
const [values, setValues] = useState({
name1: '',
...
name60: '',
});
Set state in event handler as
const handleChange = (e) => {
setValues({
...values,
[e.target.name]: e.target.value
})
}
<TextField
fullWidth
label="Name"
name="name1"
onChange={props.handleChange}
required
value={props.values.name1}
variant="outlined"
/>
.
.
.
.

React JS Typescript input onChange and onFocus error

I want to implement the following repo available on Github using ReactJS Typescript. I created 3 different methods as onChange, changeHandler, focusHandler but they are not working correctly. When I click on the Card Number field, I get a 'number.replace' error.
I need to fix onChange and onFocus methods in TextField fields.
https://github.com/amaroteam/react-credit-cards
import React, {useState, FocusEvent, ChangeEvent} from 'react'
import Cards from 'react-credit-cards';
import 'react-credit-cards/es/styles-compiled.css'
const PaymentMethodEditor = () => {
const [stateList, setState] = React.useState(initialValues)
const handleFormSubmit = async (values: any) => {
console.log(values)
}
const focusHandler = (event: React.FocusEvent<HTMLInputElement>) => {
setState({ focus: event.target.name })
}
const changeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setState({ [name]: event.target.value })
}
onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.currentTarget.value;
setState({ [name]: event.target.value })
}
return (
<CustomerDashboardLayout>
<DashboardPageHeader
icon={CreditCard}
title={`${id === 'add' ? 'Add New' : 'Edit'} Payment Method`}
button={
<Link href="/payment-methods">
<Button color="primary" sx={{ bgcolor: 'primary.light', px: '2rem' }}>
Back to Payment Methods
</Button>
</Link>
}
/>
<div id="PaymentForm">
<Cards
cvc={stateList.cvc}
expiry={stateList.exp}
focused={stateList.focus}
name={stateList.name}
number={stateList.card_no}
/>
<Card1>
<Formik
initialValues={initialValues}
validationSchema={checkoutSchema}
onSubmit={handleFormSubmit}
>
{({ values, errors, touched, handleChange, handleBlur, handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Box mb={4}>
<Grid container spacing={3}>
<Grid item md={6} xs={12}>
<TextField
name="card_name"
label="Card Name"
fullWidth
onBlur={handleBlur}
onChange={changeHandler}
onFocus={focusHandler}
value={values.card_name || ''}
error={!!touched.card_name && !!errors.card_name}
helperText={touched.card_name && errors.card_name}
/>
</Grid>
<Grid item md={6} xs={12}>
<TextField
name="card_no"
label="Card Number"
fullWidth
onBlur={handleBlur}
onChange={changeHandler}
onFocus={focusHandler}
value={values.card_no || ''}
error={!!touched.card_no && !!errors.card_no}
helperText={touched.card_no && errors.card_no}
/>
</Grid>
<Grid item md={6} xs={12}>
<TextField
name="name"
label="Name on Card"
fullWidth
onBlur={handleBlur}
onChange={handleChange}
value={values.name || ''}
error={!!touched.name && !!errors.name}
helperText={touched.name && errors.name}
/>
</Grid>
<Grid item md={6} xs={12}>
<TextField
name="exp"
label="Exp. Date"
fullWidth
onBlur={handleBlur}
onChange={handleChange}
value={values.exp || ''}
error={!!touched.exp && !!errors.exp}
helperText={touched.exp && errors.exp}
/>
</Grid>
<Grid item md={6} xs={12}>
<TextField
name="cvc"
label="CVC"
fullWidth
onBlur={handleBlur}
onChange={handleChange}
value={values.cvc || ''}
error={!!touched.cvc && !!errors.cvc}
helperText={touched.cvc && errors.cvc}
/>
</Grid>
</Grid>
</Box>
<Button type="submit" variant="contained" color="primary">
Save Changes
</Button>
</form>
)}
</Formik>
</Card1>
</div>
</CustomerDashboardLayout>
)
}
const initialValues = {
card_no: '',
name: '',
exp: '',
cvc: '',
focus: '',
number: '',
card_name: '',
}
export default PaymentMethodEditor
enter image description here
enter image description here

React useEffect(), fetch data with React Hooks and set the formik form

I want to fetch these (title, description, category) values to the following form. how can I do this?. I'm working on a Formik form that needs to adjust dynamically depending on data. I want to set data to the correct form field when the user going to edit something. I think something missing in my code. any help would be great.
const PostEdit = ({ match, history }) => {
const postId = match.params.id
//Data
const [initialValues, setInitialValues] = useState({
title: '',
description: '',
category: '',
})
const dispatch = useDispatch()
const postDetails = useSelector((state) => state.postDetails)
const { loading, error, post} = postDetails
useEffect(() => {
if (!post.title || post._id !== postId) {
dispatch(listPostDetails(postId))
} else {
setInitialValues({
title: post.title,
description: post.description,
category: post.category
})
}
}, [dispatch, history, postId, post,])
const submitHandler = () => {}
return (
<>
<div>
<Grid>
<Grid item xs={12}>
<Papervariant='outlined'>
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={submitHandler}
>
{({ dirty, isValid, values }) => {
return (
<Form>
<DialogContent>
<Grid item container spacing={1} justify='center'>
<Grid item xs={12} sm={12} md={12}>
<Field
label='Title'
name='title'
required
value={values.title}
component={TextField}
/>
</Grid>
<Grid item xs={12} sm={12} md={12}>
<Field
label='Description'
name='description'
value={values.description}
component={TextField}
/>
</Grid>
<Grid item xs={12} sm={12} md={12}>
<Field
label='Category'
name='category'
value={values.category}
component={TextField}
/>
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button
disabled={!dirty || !isValid}
variant='contained'
type='Submit'
>
Add
</Button>
</DialogActions>
</Form>
)
}}
</Formik>
</Paper>
</Grid>
</Grid>
</div>
</>
)
}
export default PostEdit
You are missing this prop
enaleReinitialize={true}
So, it should be something like this
<Formik
enableReinitialize={true} // You missed this prop
validateOnChange={true}
initialValues={initialValues}
Formik can be use as hook. https://formik.org/docs/api/useFormik
It'll exposed a function setValues and you can use it to dynamically change the form data

How disable the auto reset form on submit in formik?

I have a form that i'm controlling by formik, when i fill all the fields and press the buttom submit, the function onSubmit is called and my form have this values reseted.
Sometimes my data is incorrect (like a duplicate email) and i need to persist this data.
How i can do this?
This is my code:
const schema = Yup.object().shape({
login: Yup.string()
.email('Email não possui formato válido')
.required('Informe o email!'),
password: Yup.string().required('Informe a senha!'),
})
const formik = useFormik({
initialValues: {
login: '', password: '', inactive: false
},
validationSchema: schema,
onSubmit: values => {
registerUser(values)
}
})
return (
<form onSubmit={formik.handleSubmit} className={classes.form} noValidate>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography className={classes.observation} component="h6">* Necessário preenchimento do cadastro geral para liberar permissão de telas</Typography>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.login}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.login ? formik.errors.login : ""}
error={formik.touched.login && Boolean(formik.errors.login)}
variant="outlined"
margin="normal"
required
fullWidth
id="email"
label="E-mail"
name="login"
autoComplete="email"
/>
</Grid>
<Grid item xs={5}>
<TextField
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
helperText={formik.touched.password ? formik.errors.password : ""}
error={formik.touched.password && Boolean(formik.errors.password)}
variant="outlined"
margin="normal"
required
fullWidth
type="password"
id="password"
label="Senha"
name="password"
/>
</Grid>
<Grid item xs={2}>
<FormControlLabel
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.inactive}
control={<Switch color="primary" />}
label="Inativo"
labelPlacement="top"
/>
</Grid>
<Grid item xs={3}>
<Button fullWidth
variant="contained"
color="primary"
type="submit"
>
Cadastrar
</Button>
</Grid>
</Grid>
</form>
);
Use the Form from formik, and the default is to not reset on submit:
import { Formik, Form } from "formik";
function DemoComp(){
return(
<Formik
initialValues={{ fieldOneVal: "" }}
onSubmit={async (formsData, {setSubmitting, resetForm}) => {
setSubmitting(true)
// async request
// --> if wanted to reset on submit: resetForm();
console.log(formsData)
setSubmitting(false)
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}
You need to update the following line:
<form onSubmit={(e) => { e.preventDefault(); formik.handleSubmit(e)}} className={classes.form} noValidate>
You need to define the function to be async and as async response handling is not mention in your code so it's hard to give exact solution
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={async (values, { resetForm }) => {
// setFormvalues(({fieldOneVal:values.fieldOneval}) don't know why you're manipulating state
const resp=await someAsyncFunc()
if (resp){
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
I faced the same problem formik resetting the form before i get a response from the server.This solution helped me.
import { Formik, Form } from "formik";
function DemoComp(){
const [formvalues,setFormvalues]= useState({
{ fieldOneVal: "" }
)
return(
<Formik
initialValues={{ fieldOneVal: formvalues.fieldOneVal }}
onSubmit={(values, { resetForm }) => {
setFormvalues(({fieldOneVal:values.fieldOneval})
// async request
if sucess{
reset the state to initial values}
else{
pop up modal display with errors}
}}
>
{({ values, isSubmitting, handleChange, handleBlur, handleSubmit }) => (
<Form>
<input
type="text"
name="fieldOneVal"
value={values.fieldOneVal}
onChange={handleChange}
onBlur={handleBlur}
/>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
)
}

Resources