Formik API : send different value in handleSubmit based on button click - javascript

I have the following code of a child component which is sending the form values to the parent when a user clicks .
Save and Continue button
Submit button
The Save and Continue button in the code is defined as follows:
<div className="form-field">
<Button size="large" variant="contained" color="primary" style={{marginLeft: '5px'}} type="submit">Save & Continue</Button>
</div>
When a user clicks Save and Continue button, I want to return requestStatuses: props.SimpleRequest && props.SimpleRequest.statusId || '10',.
However, when a user clicks the following Submit button:
<Button size="large" variant="contained" color="primary"
type="submit">Submit</Button>
I want to return props.SimpleRequest && props.SimpleRequest.statusId || '6',.
The default value for Status is 6 when a user interacts with the form and the dropdown is disabled so user can't change it. However, I want to send different values of it as I explained above based on different button clicks. Is it possible?
Minimal Code with relavent Formik form information is below:
const SimpleRequestForm = (props) => {
const {values, setFieldValue, touched, errors, isSubmitting, handleReset, handleChange} =
props;
const growl = React.createRef()
return (
<div>
<div id="formDiv">
<Growl ref={growl}/>
<Form className="form-column-3">
<div className="SimpleRequest-form">
<div className="form-field">
<CustomSelectField name="requestStatuses" disabled type="select" placeholder="Status"/>
</div>
<div className="form-field">
<CustomSelectField name="requestPrioritieses" type="select" value='Normal' placeholder="Priority"/>
</div>
<div className="form-field">
<CustomSelectField name="assignees" type="select" placeholder="Assignee"/>
</div>
<div className="form-field">
<Button size="large" variant="contained" color="primary" style={{marginLeft: '5px'}} type="submit">Save & Continue</Button>
</div>
</div>
<div className="btn-group-right">
<Button size="large" variant="contained" color="primary"
type="submit">Submit</Button>
<Button size="large" variant="contained" color="primary" onClick={handleReset}
style={{marginLeft: '5px'}} type="button">Reset</Button>
<Button size="large" variant="contained" color="primary" onClick={props.onCancel}
style={{marginLeft: '5px'}} type="button">Cancel</Button>
</div>
</Form>
</div>
</div>
)
};
export const SimpleRequestEnhancedForm = withFormik(
{
mapPropsToValues: props => {
return {
requestId: props.SimpleRequest && props.SimpleRequest.requestId || '',
requestStatuses: props.SimpleRequest && props.SimpleRequest.statusId || '6',
requestPrioritieses: props.SimpleRequest && props.SimpleRequest.priorityId || '3',
assignees: props.SimpleRequest && props.SimpleRequest.assigneeId || '',
}
},
validationSchema:validationSchema,
handleSubmit(values, {props, resetForm, setErrors, setSubmitting}) {
console.log("submit Simple Request Form....")
values.assets = JSON.parse(sessionStorage.getItem('uploadedFiles'));
props.handleSubmit(values)
setSubmitting(false)
},
setFieldValue(field, value, shouldVal) {
console.log('In setFieldValue')
},
displayName: 'Simple Request Form',
})(SimpleRequestForm)

Related

React state change from within button's click handler is preventing form submission

Consider the code below:
function Item({name, _key})
{
console.log('rendering Item')
const [updatingName, setUpdatingName] = useState(false);
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input ref={nameInputElement} type="text" defaultValue={name} name="name"
disabled={!updatingName} />
{!updatingName
? <>
<button key={1} type="button" onClick={onUpdateClick}>Update</button>
<button key={2} type="submit" name="delete" value={_key}>Remove</button>
</>
: <>
<button key={3} type="submit" name="update" onClick={(e) => {setUpdatingName(false)}}>Save</button>
<button key={4} type="button" onClick={onCancelClick}>Cancel</button>
</>}
</div>
)
}
function ItemList({title})
{
return <>
<h1>{title}</h1>
<form method="post" onSubmit={(e) => {console.log('submitting');e.preventDefault()}}>
<Item name={'small'} _key={0} />
</form>
</>
}
export default ItemList;
The problem that I am facing is the click of the Save button. When it's clicked, as you can see, I trigger a state change. But at the same time, I also want the button to cause the underlying <form>'s submission.
(To check whether the form is submitted, I've prevented its default submit mechanism and instead gone with a simple log.)
However, it seems to be the case that when the state change is performed from within the onClick handler of the Save button, it ceases to submit the form. If I remove the state change from within the handler, it then does submit the form.
Why is this happening?
Live CodeSandbox demo
When you call setUpdatingName(false) in save button's click handler, the button is removed from the DOM before submitting. You can add the logic for showing the buttons in ItemList, like below:
function ItemList({ title }) {
const [updatingName, setUpdatingName] = useState(false);
return (
<>
<h1>{title}</h1>
<form
method="post"
onSubmit={(e) => {
e.preventDefault();
setUpdatingName(false);
console.log("submitting");
}}
>
<Item
name={"small"}
_key={0}
updatingName={updatingName}
setUpdatingName={setUpdatingName}
/>
</form>
</>
);
}
export default ItemList;
function Item({ name, _key, updatingName, setUpdatingName }) {
console.log("rendering Item");
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input
ref={nameInputElement}
type="text"
defaultValue={name}
name="name"
disabled={!updatingName}
/>
{!updatingName ? (
<>
<button key={1} type="button" onClick={onUpdateClick}>
Update
</button>
<button key={2} type="submit" name="delete" value={_key}>
Remove
</button>
</>
) : (
<>
<button key={3} type="submit" name="update">
Save
</button>
<button key={4} type="button" onClick={onCancelClick}>
Cancel
</button>
</>
)}
</div>
);
}
Also, you could use useTransition to ask React to delay the state update, so the submission happens first:
function Item({ name, _key }) {
console.log("rendering Item");
const [isPending, startTransition] = useTransition();
const [updatingName, setUpdatingName] = useState(false);
const nameInputElement = useRef();
useEffect(() => {
if (updatingName) {
nameInputElement.current.focus();
}
}, [updatingName]);
function onUpdateClick() {
setUpdatingName(true);
}
function onCancelClick() {
setUpdatingName(false);
}
return (
<div>
<input
ref={nameInputElement}
type="text"
defaultValue={name}
name="name"
disabled={!updatingName}
/>
{!updatingName ? (
<>
<button key={1} type="button" onClick={onUpdateClick}>
Update
</button>
<button key={2} type="submit" name="delete" value={_key}>
Remove
</button>
</>
) : (
<>
<button
key={3}
type="submit"
name="update"
onClick={(e) => {
startTransition(() => setUpdatingName(false));
}}
>
Save
</button>
<button key={4} type="button" onClick={onCancelClick}>
Cancel
</button>
</>
)}
</div>
);
}

Save value in react js

I have a form with sub forms.
I have submit button for outer form but in the same time and for inner. The outer form works fine, it saves all data. but i can't get values from inner form clicking on
<Form.Item>
<Button type="primary" htmlType="submit">
Submit Inner
</Button>
</Form.Item>
Clicking on that i want to get values inside inner component in:
const onFinish = v => {
console.log("inner", v);
};
The subform code:
<Form.List onFinish={onFinish} name={[props.fieldKey, "inner"]}>
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<div>
<Form.Item
// name={"aar"}
{...field}
name={[field.name, "innerName"]}
fieldKey={[field.fieldKey, "innerName"]}
key={index}
noStyle
>
<Input
placeholder="passenger name"
style={{ width: "60%" }}
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit Inner
</Button>
</Form.Item>
</div>
))}
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "60%" }}
>
<PlusOutlined /> Add field
</Button>
</div>
);
}}
</Form.List>
But when i click on this i get values in the outer form.
Question: How to get values from inner form clicking on Submit Inner button?
demo: https://codesandbox.io/s/wonderful-ives-o81ue?file=/SubForm.js
now i get:
expected result:

Bootstrap Modal goes blank after button click

I am trying to call a Modal function. When I click to view it, it doesn't render and the page goes blank(white).
This is the code for
BootstrapModal :
class BootstrapModal extends React.Component{
constructor(){
super();
this.state = {
showHide : false
}
}
handleModalShowHide() {
console.log("hitting");
this.setState({ showHide: !this.state.showHide })
}
render(){
return(
<div>
<Button variant="third" id="btn-third" onClick={() => this.handleModalShowHide()}>
Send Email
</Button>
<Modal show={this.state.showHide}>
<Modal.Header closeButton onClick={() => this.handleModalShowHide()}>
<Modal.Title>Email Chart To User</Modal.Title>
</Modal.Header>
<Modal.Body>
<FormGroup>
<Modal.Label>Email address</Modal.Label>
<Modal.Input
type="email"
placeholder="Email"
/>
</FormGroup>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => this.handleModalShowHide()}>
Cancel
</Button>
<Button variant="primary" onClick={() => this.handleModalShowHide()}>
Send
</Button>
</Modal.Footer>
</Modal>
</div>
)
}
}
export default BootstrapModal;
Any ideas on why this is happening? Any suggestions would be gladly appreciated.
I think your problem is that you have not binded the handleModalShowHide() function. You can aviod having to do thst using an arrow function:
handleModalShowHide = () => {
Code here
}
I had to change
<FormGroup>
<Modal.Label>Email address</Modal.Label>
<Modal.Input
type="email"
placeholder="Email"
/>
</FormGroup>
To
<FormGroup>
<label for="message-text" class="col-form-label">Email Adress:</label>
<input type="text" class="form-control" id="recipient-name"></input>
</FormGroup>
After changing this, the Modal successfully rendered.

Formik lost fields when trigger a modal confirm

I have a form using Formik library, all are right but when i want to confirm and submit i need to pass first a modal, the problem is when i launch the confirm modal all data i put in the form are eliminate and nothing is send, i noticed when the i launch the modal, the form tag are upload and then lost the data, someone has the same problem ? o are something to prevent the form tag upload when change the state of the modal ?
here is part of my code, i use CSSTransition on the modal, that mount and unmount the component, and i call previous fields on the form using FieldArray
<Formik
enableReinitialize
initialValues={INITIAL_VALUES}
onSubmit={(values) => {
this.props.onSubmitForm(values.rows);
}}
>
{({ values, errors, touched, isValid }) => (
<Form>
<Title />
<div className="wrapper__brick wrapper__brick--to-up">
<FieldArray
name="rows"
render={({ push }) => (
<>
<div className="wrapper__block">
<div className="master-table">
<FieldArray
name="rows"
render={({ remove }) => (
<div className="master-table__container">
{values.rows.length > 0 &&
values.rows.map((rows, index) => (
<div
className="master-table__row"
key={index}
>
<div className="master-table__item">
<Field
className={errors.rows && errors.rows[index] && touched.rows && touched.rows[index] ?
'input input--empty is-danger'
:
'input input--empty'
}
name={`rows.${index}.name`}
placeholder="Name"
type="text"
validate={validateName}
/>
<ErrorMessage
name={`rows.${index}.name`}
component="p"
className="help is-danger"
/>
</div>
<div className="master-table__item">
<div className={rows.default ? 'select select--disabled' : 'select select--empty'}>
<Field
as="select"
disabled={rows.default}
name={`rows.${index}.kind`}
>
{this.allowedKinds.map((row) => (
<option
value={row.internal}
key={row.internal}
>
{row.name}
</option>
))}
</Field>
</div>
</div>
<div className="master-table__item">
<button
className="button button--trigger tooltip is-tooltip-right"
data-tooltip={rows.default ? t('common.deleteNotAvailable') : t('common.delete')}
onClick={() => remove(index)}
type="button"
disabled={rows.default}
>
<span className="icon">
<i className="far fa-trash-alt" />
</span>
</button>
</div>
</div>
))}
</div>
)}
/>
</div>
</div>
<Footer
onAddRow={() => push({
id: UUID.v4(),
name: '',
kind: 'string',
type: 'generic',
required: false,
default: false
})}
validForm={!isValid}
/>
<TransitionWrapper stateToggle={this.state.openModal}>
<ModalDialog
iconModal="fas fa-info-circle"
titleText={t('modals.descriptionContinue')}
onCloseMethod={this.handleShowModal}
onAcceptMethod={this.props.onSubmitForm}
/>
</TransitionWrapper>
</>
)}
/>
</div>
</Form>
)}
</Formik>

How to redirect textfields enter command of going to form submit instead of button midway form?

I'm using material UI as my component library. I have a small dialog that has a "recover password" button placed somewhere inside the form. - I notice that after adding this button the "enter" command in the textfields becomes the onClick command of the buttons.
The form is simply like:
type PropTy = {
classes: any,
submit: (Event) => mixed;
handleClose: (Event) => mixed;
handleRequestPasswordRecover: (Event) => mixed;
};
function SigninForm(props:PropTy) {
const {classes, submit, handleClose, handleRequestPasswordRecover} = props;
const signinRef = React.createRef();
const actions = [
<Button
type="reset"
label="Reset"
color="secondary"
style={{ float: 'left' }}
key='reset'
>Reset</Button>,
<Button
label="Cancel"
color="primary"
onClick={handleClose}
key='cancel'
>Cancel</Button>,
<Button
type="submit"
label="Submit"
variant="contained"
color="primary"
key='submit'
autoFocus
>Login</Button>,
];
return (
<form className={classes.form}
onSubmit={submit}
ref={signinRef}
>
<FormControl margin="normal" required fullWidth>
<TextField id="username" name="username" autoComplete="username" autoFocus label={'Username'}/>
</FormControl>
<FormControl margin="normal" required fullWidth>
<div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'baseline'}}>
<FormLabel htmlFor="password">Password</FormLabel>
<button className={classes.linkButton} onClick={(e) => {
handleRequestPasswordRecover(e)
}}>{'Lost password?'}</button>
</div>
<Input
name="password"
type="password"
id="password"
autoComplete="current-password"
/>
</FormControl>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<div style={{ textAlign: 'right'}}>
{actions}
</div>
</form>);
}
The action that happens on "enter" is not "submit" as I expect - but rather the button's onClick event (handleRequestPasswordRecover). How do I redirect this?
You should set the type attribute of the button with the onClick={(e) => { handleRequestPasswordRecover(e)... to "button" (i.e. <button type="button"...).
The default type of buttons is submit.
Inside submit function you can call preventDefault();
const submit = (event)=>{ event.preventDefault(); }
You can write the below code in your html on form tag. So you can prevent the form submission on hit the enter key while focus on textfield.
<form className={classes.form}
onSubmit={submit}
ref={signinRef}
onKeyPress={(event) => {
if (event.key === "Enter") {
event.preventDefault();
}
}}>

Categories