Formik Form Not submitting from Modal Component - javascript

A have some form field that is on the Normal Page and on a Modal, i want the Modal button to trigger the submit event. Whenever i use the submit type="submit" on the Modal button, i get no resposnse. But if i use it in the Normal page button it works. Please what's going on, can't i use it in the Modal.
<Formik
initialValues={{
productName: "",
productNumber: "",
quantity: 1,
unitCost: 0,
totalCost: 0,
customerName: "",
customerNumber: "",
amount: "",
}}
onSubmit={(data, { setSubmitting }) => {
setSubmitting(true);
setTimeout(() => {
console.log(data);
alert(JSON.stringify(data, null, 2));
setSubmitting(false);
}, 2000);
}}
>
{({
values,
handleBlur,
handleChange,
setFieldValue,
isSubmitting,
}) => (
<Form>
<Box>
<Grid templateColumns="repeat(2, 1fr)" gap={5}>
<Box>
<FormLabel>Product Name:</FormLabel>
<Field
as={Input}
name="productName"
type="text"
placeholder="Product Name:"
/>
</Box>
<Box>
<FormLabel>Product Number:</FormLabel>
<Field
as={Input}
name="productNumber"
type="number"
placeholder="Product Number:"
/>
</Box>
<Box>
<FormLabel>Quantity:</FormLabel>
<Field
as={Input}
name="quantity"
type="number"
value={values.quantity}
onChange={handleChange}
onBlur={handleBlur}
placeholder="Quantity:"
/>
</Box>
<Box>
<FormLabel>Unit Cost:(in Naira)</FormLabel>
<Field
as={Input}
name="unitCost"
type="number"
value={values.unitCost}
onChange={handleChange}
onBlur={handleBlur}
placeholder="Unit Cost:"
/>
</Box>
<Box>
<FormLabel>Total Cost:(in Naira)</FormLabel>
<CalculatedField
type="number"
name="totalCost"
values={values}
value={values.totalCost}
setFieldValue={setFieldValue}
onChange={handleChange}
onBlur={handleBlur}
/>
</Box>
</Grid>
<Button mt={4} colorScheme="green" onClick={openIt} isFullWidth >
// If used here, it will work... but i don't want to use it here
Order Now
</Button>
</Box>
<Modal closeOnOverlayClick={true} isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Box>
<Grid templateColumns="repeat(2, 1fr)" gap={5}>
<Box>
<FormLabel>Customer Name: </FormLabel>
<Field
as={Input}
name="customerName"
type="text"
placeholder="Customer Name:"
/>
</Box>
<Box>
<FormLabel>Customer Number: </FormLabel>
<Field
as={Input}
name="customerNumber"
type="text"
placeholder="Customer Number:"
/>
</Box>
<Box>
<FormLabel>Amount: </FormLabel>
<Field
as={Input}
name="amount"
type="text"
placeholder="Amount:"
/>
</Box>
</Grid>
</Box>
</ModalBody>
<ModalFooter>
<Button colorScheme="green" type="submit" >
// i want to use it here
Pay Now
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Form>
)}
</Formik>

I don't really understand what you want exactly, but if you want to trigger the submit, you could do with your normal button.
First of all, pass submitForm or handleSubmit as props with your others ones
{({
submitForm or handleSubmit,
values,
handleBlur,
handleChange,
setFieldValue,
isSubmitting,
}) => (
Then on your butotn, remove the type submit and add an event handler on click
<Button colorScheme="green" onClick={submitForm // or handleSubmit}>
Pay Now
</Button>
Im sorry i don't know 100% which one will work, it's been a while im not using React an formik.
But remember, when something not working like you want, try to thing another way to do it. Typically trigger the submit manually with an event handler

Related

Why my handleChange is not being invoked? MaterialUI

Is there something wrong with the TextField component from Material UI that I'm missing?
My handleChange simply is not getting invoked.
I can type in value in the inputs, but state of the component is not changing.
Here is the Auth component:
const Auth = () => {
const [formData, setFormData] = useState(initialFormState)
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
}
const handleChange = (e) => {
setFormData({
...formData,
[e.target.name]: e.target.value
})
}
return (
<Container component="main" maxWidth="xs">
<Paper className={classes.paper} elevation={3}>
<form className={classes.form} onSubmit={handleSubmit}>
<Grid container spacing={2}>
<Input name="email" label="e-mail" handleChange={handleChange} type="email" />
<Input name="password" label="password" handleChange={handleChange} type={showPassword ? "text" : "password"} handleShowPassword={handleShowPassword} />
</Grid>
<Button type="submit" variant="contained" color="primary" className={classes.submit} fullWidth>
{isSignup ? "Sign up" : "Sign in"}
</Button>
</form>
</Paper>
</Container>
);
}
And the input component which is inside Auth:
const Input = ({ name, half, handleChange, type, label, autoFocus, handleShowPassword }) => {
return (
<>
<Grid item xs={12} sm={half ? 6 : 12}>
<TextField
name={name}
handleChange={handleChange}
variant="outlined"
required
fullWidth
label={label}
autoFocus={autoFocus}
type={type}
InputProps={name === "password" ? {
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleShowPassword}>
{type === "password" ? <Visibility/> : <VisibilityOff/>}
</IconButton>
</InputAdornment>
)
} : null}
/>
</Grid>
</>
);
}
You've to change the input attribute from handleChange to onChange
<Input name="email" label="e-mail" onChange={handleChange} type="email" />
<Input name="password" label="password" onChange={handleChange} type={showPassword ? "text" : "password"} handleShowPassword={handleShowPassword} />

How do I get the value from Form.Control in React Bootstrap?

Here is my code :
<Modal centered size="lg" show={showAlertModal} onHide={handleCloseAlertModal}>
<Modal.Header>
<Modal.Title>{dpAlert !== null && dpAlert.id !== null ? `Alert #${dpAlert.id} - Editing` : `New Alert`}</Modal.Title>
</Modal.Header>
<Form onSubmit={handleSubmit}>
<Modal.Body>
<Form.Group controlId="language">
<Form.Label>Language</Form.Label>
<Form.Control id='inputL' onChange={(value) => setInputLanguage} type="text" placeholder="Language" required />
<Form.Text className="text-muted">
This is used for internal reference only, not shown to the public
</Form.Text>
</Form.Group>
<hr />
<b>Preview:</b>
{getAlertPreview(dpAlert)}
</Modal.Body>
<Modal.Footer>
<Button type="reset" variant="danger" size="lg" onClick={handleCloseAlertModal}>
Close
</Button>
<Button type="submit" variant="primary" size="lg" onClick={handleSubmit} form="newAlert">
Save
</Button>
</Modal.Footer>
</Form>
</Modal>
I am trying to get the value from
<Form.Control id='inputL' onChange={(value) => setInputLanguage} type="text" placeholder="Language" required />
and I have tried the onChange to set the value in a state but it's not working? Any help is appreciated thank you
You can get with event.target.value
const setInputLanguage = event => {
console.log(event.target.value);
}
<Form.Control id='inputL' onChange={(value) => setInputLanguage} type="text" placeholder="Language" required />
OR
<Form.Control id='inputL' onChange={event => console.log(event.target.value)} type="text" placeholder="Language" required />

TypeError: Cannot read property 'style' of null on TextareaAutosize

I am having trouble with unit snapshot testing and cant figure why.
I am getting the following error:
enter image description here
The component is actually a Form with 3 fields: Full name, Email and Note. There is also a checkbox which controls the Email and Note field in case we dont want to put that information in the form.
For the Note I am using TextareaAutosize, so that the text area is re sizable (due to requirements).
const [missingInfo, setMissingInfo] = useState(false);
const initialValues = {
fullName: '',
email: '',
note: '',
};
return (
<Formik
initialValues={initialValues}
validationSchema={object({
fullName: string().required('Must contain a full name'),
})}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(true);
...
}}
>
<Form>
<Typography>Title</Typography>
<HashLink
to={{ hash: '#xxx' }}
onClick={() => toggleHash()}
>
Changed your mind?
</HashLink>
<Typography>Full name</Typography>
<Field name="fullName">
{({ field }: FieldProps) => (
<TextField
id="fullName"
variant="outlined"
type="text"
fullWidth
{...field}
/>
)}
</Field>
<ErrorMessage name="fullName">
{msg => <div className={styles.errorMessage}>{msg}</div>}
</ErrorMessage>
<FormControlLabel
control={
<Checkbox
checked={missingInfo}
onChange={() => setMissingInfo(!missingInfo)}
name="missingInfo"
/>
}
label="No info?"
/>
{!missingInfo && (
<>
<Typography>Email</Typography>
<Field name="email">
{({ field }: FieldProps) => (
<TextField
id="email"
variant="outlined"
type="text"
fullWidth
{...field}
/>
)}
</Field>
<Typography>Note</Typography>
<Field name="note">
{({ field }: FieldProps) => (
<TextareaAutosize
rowsMin={3}
className={styles.textArea}
{...field}
/>
)}
</Field>
</>
)}
<Button
variant="contained"
type="submit"
>
Apply
</Button>
</Form>
</Formik>
)
The error is as I said in the snapshot test:
test('matches snapshot', () => {
const tree = renderer
.create(
<BrowserRouter>
<MyComponent {...props} />
</BrowserRouter>,
)
.toJSON();
expect(tree).toMatchSnapshot();
});
Can someone please help?

Formik OnSubmit Not Getting Triggered

I am working on a react project and i am using Formik for forms. For some reason, the onSubmit method doesnt get triggered. I have been trying to figure out where the error is but i have couldnt.
I have an almost similar setup on another component and that works fine. Any help is appreciated.
There are no issues with validation, because the button becomes enabled only if it satisfies the validation parameters. I click the submit button and nothing happens. I have tried debugging but its not even hitting the onSubmit method.
<Segment>
<Formik
initialValues={{
comments: "",
mk1: "",
mk2: "",
mk3: "",
mk4: "",
mk1Num: 0,
mk2Num: 0,
mk3Num: 0,
mk4Num: 0,
}}
validationSchema={Yup.object({
comments: Yup.string().required(),
mk1: Yup.string().required(),
mk2: Yup.string().required(),
mk3: Yup.string().required(),
mk4: Yup.string().required(),
mk1Num: Yup.number().positive().max(5),
mk2Num: Yup.number().positive().max(5),
mk3Num: Yup.number().positive().max(5),
mk4Num: Yup.number().positive().max(5),
})}
onSubmit={async (values, { setErrors, setSubmitting }) => {
try {
console.log(values);
const totalGrade =
values.mk1Num + values.mk2Num + values.mk3Num + values.mk4Num;
await addToSubmittedAssignment(
courseId,
assignmentId,
values,
totalGrade
);
setSubmitting(false);
} catch (error) {
setErrors({ err: error.message });
}
}}
>
{({ isSubmitting, isValid, dirty, errors, values }) => (
<Form className='ui form'>
<TextArea
name='comments'
placeholder='Enter Comments Here'
rows={10}
/>
<Grid>
<Grid.Column width={14}>
<TextInput name='mk1' placeholder='Enter Marking Key 1' />
<TextInput name='mk2' placeholder='Enter Marking Key 2' />
<TextInput name='mk3' placeholder='Enter Marking Key 3' />
<TextInput name='mk4' placeholder='Enter Marking Key 4' />
</Grid.Column>
<Grid.Column width={2}>
<TextInput name='mk1Num' type='number' />
<TextInput name='mk2Num' type='number' />
<TextInput name='mk3Num' type='number' />
<TextInput name='mk4Num' type='number' />
</Grid.Column>
</Grid>
{errors.err && (
<Label
basic
color='red'
style={{ marginBottom: 10 }}
content={errors.err}
/>
)}
<br />
<Button
loading={isSubmitting}
disabled={!isValid || !dirty || isSubmitting}
type='submit'
fluidsize='large'
color='teal'
content='Submit'
/>
</Form>
)}
</Formik>
</Segment>
Also, i am using Semantic UI react for styling.
Try adding the submit method to Form render params:
{({ isSubmitting, submitForm, isValid, dirty, errors, values }) => (...
And then call it on submit button:
<Button
loading={isSubmitting}
disabled={!isValid || !dirty || isSubmitting}
type='submit'
fluidsize='large'
color='teal'
content='Submit'
onClick={submitForm}
/>
I had this issue and it turned out to be Yup silent failing a validation check. I simply removed the .required() from some of the object's properties to get it to work.

Set first fields open in a dynamic form

I have a dynamic form where users can add data. By default i want to set the form in this way:
How you can see, the first pair of input is open when user opens the application.
I made this by changing this:
const Demo = () => {
const onFinish = values => {
console.log("Received values of form:", values);
};
return (
<Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.List name="users">
{(fields, { add, remove }) => {
console.log(fields);
return (
<div>
{fields.map(field => (
<Space
key={field.key}
style={{ display: "flex", marginBottom: 8 }}
align="start"
>
<Form.Item
{...field}
name={[field.name, "first"]}
fieldKey={[field.fieldKey, "first"]}
rules={[{ required: true, message: "Missing first name" }]}
>
<Input placeholder="First Name" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "last"]}
fieldKey={[field.fieldKey, "last"]}
rules={[{ required: true, message: "Missing last name" }]}
>
<Input placeholder="Last Name" />
</Form.Item>
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
>
<PlusOutlined /> Add field
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
to this:
const Demo = () => {
const onFinish = values => {
console.log("Received values of form:", values);
};
const firstDefaultOpen = {
name: 0,
key: 0,
isListField: true,
fieldKey: 0
};
return (
<Form name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.List name="users">
{(fields, { add, remove }) => {
console.log(fields);
return (
<div>
{fields.concat(firstDefaultOpen).map(field => (
<Space
key={field.key}
style={{ display: "flex", marginBottom: 8 }}
align="start"
>
<Form.Item
{...field}
name={[field.name, "first"]}
fieldKey={[field.fieldKey, "first"]}
rules={[{ required: true, message: "Missing first name" }]}
>
<Input placeholder="First Name" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, "last"]}
fieldKey={[field.fieldKey, "last"]}
rules={[{ required: true, message: "Missing last name" }]}
>
<Input placeholder="Last Name" />
</Form.Item>
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
block
>
<PlusOutlined /> Add field
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
Issue: But appears a problem when i try to add another input, because writing on first pair of inputs i can see the same text on the next inputs. Probably this is hapenening because of the same ids.
Question: How to set default open first pair of input as in the image using the code above?
demo: https://codesandbox.io/s/hungry-star-nu5ld?file=/index.js:235-2322
ps: i know that exists the next solution:
<Form initialValues={{ users: [""] }} name="dynamic_form_nest_item" onFinish={onFinish} autoComplete="off">
<Form.List name="users">
{(fields, { add, remove }) => {
console.log(fields);
return (
<div>
{fields.map(field => (
...
...
But i don't want this solution because i can't interact with <Form/> tag in my real application, so even this could be a solution, but i need another, like mine with concat() but of course to be workable.

Categories