method is not getting called on onChange event in formik react - javascript

I have to call below method using formik
const handleChange = async (e:any, values: any) => {
alert(e.target.value);
alert(values);
alert('Method called');
};
below is formik code.
<Formik initialValues={formInitialSchema}
validationSchema={formValidationSchema}
onSubmit={handleSubmit}>
<Form>
<div className="col-md-4">
<label htmlFor="protoColNo">Protocol No</label>
<Field
id="protoColNo"
className="form-control"
name="protoColNo"
placeholder="Enter the Protocol No"
/>
<p className="text-danger">
<ErrorMessage name="protoColNo" />
</p>
</div>
<div className="col-md-4">
<label htmlFor="activerequests">Active Requests</label>
<select
name="activeRequest"
style={{ display: 'block' }}
onChange= {(e)=>handleChange}>
<option value="No" >No </option>
<option value="Yes" >Yes</option>
<option value="All" selected>All </option>
</select>
<p className="text-danger">
<ErrorMessage name="activerequests" />
</p>
</div>
</div>
</Form>
</Formik>
I have one input filed and one drop down. As soon as user change the value of drop down I need to call handleChange method with the value of input filed and list. but method is not getting called. I dont know what wrong I am doing?
can you please help me with the same?

onChange= {(e)=>handleChange(e)}> //you forgot to call the handleChange
OR
onChange={handleChange}

You need to call the anonymous function inside the onChange event.
Use the following code :
onChange= {(e)=>handleChange(e)}

Related

Validate select list with react-hook-form

I want to implement validation for React form using react-hook-form. For input value I implemented this:
<div className='input-group mb-3'>
<Controller
control={control}
name={"email"} // the key of json
defaultValue={""}
render={({ field }) => (
<input
{...field}
type="email"
className="form-control"
placeholder="Email"
aria-label="email"
onChange={(e) => field.onChange(e.target.value)}
/>
)}
/>
</div>
For me it's not clear how I need to implement it for select menu:
<div className='input-group mb-3'>
<select
className='form-control form-select'
name='budget'
id='budget'
required=''
data-msg='Please select your budget.'
>
<option value=''>Budget</option>
<option value='budget3'>More than $500,000</option>
</select>
</div>
Wat is the proper way to implement it?
somethings like this works?
<Controller
control={control}
name="budget"
rules={{
budget: {
required: "Required",
},
}}
render={({ field }) => (
<select name="budget" onChange={field.onChange} value={field.value}>
<option value="">Please select your budget</option>
<option value="budget3">More than $500,000</option>
<option value="budget2">$250,000 - $500,000</option>
<option value="budget1">$100,000 - $250,000</option>
{/* more budgets */}
</select>
)}
/>;
control is destructured from useForm like so:
const { controls, register, setValue, ...moreEls } = useForm();

Selecting an option from a dropdown list causes react app to crash

I have a react component that is a select/ option that is populated from state. When the app renders for the first time, the dropdown list populates correctly, but when I select one of the options the app crashes and I get the error 'values.appOwner.map() is not a function. I am looking to populate this form and send it to my backend server. I want to pass the selected corporation to the backend. Here is my code.
import React from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Image, Button, Badge } from 'antd';
const MobileAppCreateForm = ({
handleSubmit,
handleImage,
handleChange,
values,
preview,
uploadButtonText,
handleImageRemove
}) => {
const router = useRouter();
return (
<form className='add-content-form' onSubmit={handleSubmit}>
<div class='input-group'>
<input
type='text'
className='form-control'
placeholder='Mobile App Name'
name='appName'
value={values.appName}
onChange={handleChange}
style={{ marginRight: '.5rem' }}
/>
<select
title='Select Corporation'
name='appOwner'
className='form-select'
value={values.appOwner}
onChange={handleChange}
>
<option selected>Select a Corporation</option>
{values.appOwner &&
values.appOwner.map(corp => (
<option key={corp.corporationId} value={corp.corporationName}>
{corp.corporationName}
</option>
))}
</select>
<span
class='input-group-text ant-btn-primary'
style={{ cursor: 'pointer' }}
onClick={e => router.push('/add_content/add_corporation')}
>
Add Corporation
</span>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='Enter Mobile App Description'
name='appDescription'
value={values.appDescription}
onChange={handleChange}
/>
</div>
<div className='row'>
<div className='col-md-6'>
<input
type='text'
className='form-control'
placeholder='Mobile App Website'
name='appWebsite'
value={values.appWebsite}
onChange={handleChange}
/>
</div>
<div className='col-md-6'>
<input
type='text'
className='form-control'
placeholder='Mobile App Privacy Policy Link'
name='appPrivacyPolicyLink'
value={values.appPrivacyPolicyLink}
onChange={handleChange}
/>
</div>
</div>
<div className='row mt-3'>
<div className='col-md-4'>
<select
className='form-select'
name='appUserAccountDownload'
onChange={handleChange}
value={values.appUserAccountDownload}
>
<option selected disabled>
User Account Download
</option>
<option value='true'>True</option>
<option value='false'>False</option>
</select>
</div>
<div className='col-md-4'>
<select
className='form-select'
onChange={handleChange}
name='appLocationHistory'
value={values.appLocationHistory}
>
<option selected disabled>
User Location History
</option>
<option value='true'>True</option>
<option value='false'>False</option>
</select>
</div>
<div className='col-md-4'>
<input
type='text'
className='form-control'
placeholder='Mobile App Data Retention Length'
name='appDataRetention'
value={values.appDataRetention}
onChange={handleChange}
/>
</div>
</div>
<div className='row mt-3'>
<div className='col-md-12'>
<div className='form-group d-grid gap-2'>
<label className='btn btn-outline-secondary btn-block text-start'>
{uploadButtonText}
<input
type='file'
name='image'
onChange={handleImage}
accept='image/*'
hidden
/>
</label>
{preview && (
<div style={{ position: 'relative' }}>
<Badge
count='X'
onClick={handleImageRemove}
style={{
cursor: 'pointer',
position: 'absolute',
top: '5px',
right: '2px'
}}
>
<Image width={200} src={preview} />
</Badge>
</div>
)}
</div>
</div>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='iOS Associated Files'
name='appIosAssociatedFiles'
value={values.appIosAssociatedFiles}
onChange={handleChange}
/>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='iOS Associated Files'
name='appAndroidAssociatedFiles'
value={values.appAndoridAssociatedFiles}
onChange={handleChange}
/>
</div>
<Button
type='submit'
className='btn btn-primary ant-btn-primary'
onClick={handleSubmit}
disabled={values.loading || values.uploading}
loading={values.loading}
shape='round'
>
{values.loading ? 'Saving...' : 'Save'}
</Button>
<Button
type='submit'
className='btn btn-primary ant-btn-primary'
disabled={values.loading || values.uploading}
loading={values.loading}
shape='round'
style={{ marginLeft: '.25rem' }}
>
{values.loading ? 'Publishing...' : 'Publish'}
</Button>
</form>
);
};
export default MobileAppCreateForm;
Here is my handleChange method:
const handleChange = (e, index) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
It seems that values.appOwner is not an array so you can't call map() on it. You could check if appOwner is actually and array instead of just checking if it's truthy ({values.appOwner && ...) since this condition would pass for a simple string or number and then would crash when calling map on it. You can use Array.isArray() to instead. You should still try to debug and see what's the actual value of values.appOwner to see why is not returning an array.
Edit after adding handleChange function code
The problem is with the handleChange method and also with the way you are handling state. You should use different objects to store the selected value and the initial options for the select. If you look at your code you are using values.appOwner both as the value prop in the select tag and as an array to iterate in to build the options. Once an option is selected you update appOwner with the selected value so it stops being an array.
Something like this could work
const [corporation, setCorporation] = useState('');
....
<select
title='Select Corporation'
name='appOwner'
className='form-select'
value={corporation}
onChange={event => setCorporation(event.target.value)}
You might want to store the selected corporation in the parent component instead but the important thing here is that is separated from the values.appOwner piece

submit form in react with variable set of inputs?

//form.js
const form=({seg,onSubmit,onChange})=>{
<form id="input_form" onSubmit={onSubmit}>
{seg.map(item=>
<>
<input type="number" onChange={onChange} name={item}
type="number" required className="form-control control" id={item+1} />
</>
)}
</form>}
// app.js
state={array:[0.0,1.0], seg=3}
onSubmit=()=>{
}
onChange=()=>{
// should update the array(as this.state.array=[0.0, inputa,inputb,inputc..., 1.0])}
how do i update the array? what should be the onChange, onSubmit func?
(this.state.seg is variable).
You can use this.setState({ seg : newValue});
You can set the seg state property value like this
onChange=(event)=>{
this.setState({seg: event.target.value});
}
I suppose yo need to update the array with current seg value. If you want to do it using onSubmit, you have to use a button with type of submit. Then the button calls the onSubmit function. Try this.
<form id="input_form" onSubmit={onSubmit}>
{seg.map(item =>
<>
<input type="number" onChange={onChange} name={item} type="number" required className="form-control control" id={item + 1} />
<button type="submit">Submit</button>
</>
)}
</form>
onSubmit=()=>{
this.setState({
array: [...this.state.array, seg]
})
}

React Formik Field onChange event handle

I am trying to handle onChange for Field component in React Formik, but it doesn't work. I also tried to handle it outside Formik component by:
handleChange(e) {
console.log('changing');
}
<Field type="radio" name="players" value="1" onChange={e => this.handleChange(e)}/>
but I am getting the warning:
A component is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa).
For now my code looks like this:
<Formik
onChange={() => {
console.log('changing');
}}
onSubmit={(values) => {
console.log('submitted');
}}
>
{({ isSubmitting, handleChange }) => (
<Form>
<InputWrapper>
<span>1</span>
<Field type="radio" name="players" value="1" onChange={handleChange}/>
<span>2</span>
<Field type="radio" name="players" value="2" onChange={handleChange}/>
</InputWrapper>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Loading..' : 'Start'}
</button>
</Form>
)}
</Formik>
Any tips/ideas?
One issue I have found with introducing the onBlur:handleBlur to your Formik Field is that it overrides the Formik Validation.
Use onKeyUp={handleChange}
This solved said problem
You must to use the InputProps of Field like the following...
import { TextField } from 'formik-material-ui';
<Field
type="radio"
name="players"
value="2"
component={TextField}
InputProps={{ onBlur:handleBlur }}/>
To use the InputProps in the Field you need to use a component TextField from the formik-material-ui lib.
Another way is use the onKeyUp or onKeyDown, that functions work ok with Field and that functions are like onChange
<Field
type="radio"
name="players"
value="2"
onKeyUp =this.handleChange/>
I found one trick which worked well for me, you can use "values" of formik and call a method passing the "values" as parameter and perform the action using new values.
const handleUserChange = (userId: number) => {
//userId is the new selected userId
};
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
enableReinitialize
>
{({ isValid, isSubmitting, values }) => (
<Form>
<table className="table">
<tbody>
<tr>
<td>Users</td>
<td>
<Field name="userId" className="form-control" as="select">
<option value="">--select--</option>
{data.Users.map((user, index) => (
<option key={user.id} value={user.id}>{`User ${index + 1}`}</option>
))}
</Field>
</td>
</tr>
{handleUserChange(values.userId)}
</tbody>
</table>
<div className="row">
<div className="col-sm-12">
<SubmitButton label="Save" submitting={isSubmitting} disabled={!isValid || isSubmitting} />
</div>
</div>
</Form>
)}
</Formik>

ReactJS - Waiting for user to finish multiple inputs

I just started learning ReactJS so any help would be appreciated. I'm trying to make a form where user inputs his/her address into multiple input fields. When the user finishes typing into ALL input fields, then a function will be triggered to validate the address. Through research, I found out about onChange and onBlur but it seems like that only works for one input field. Is there any other way to keep track of all five inputs and trigger a function after the user finishes? Or if there is any way to use onChange to do so, I would love to know. The following is the code for my form. Thank you in advance.
<form>
<label>
<DebounceInput
name="addressLine1"
placeholder="Address Line 1"
debounceTimeout={300}
onChange={ (e) => this.handleChange(e, name)}
/>
</label>
<label>
<DebounceInput
name="addressLine2"
placeholder="Address Line 2"
debounceTimeout={300}
onChange={ (e) => this.handleChange(e, name)}
value={this.state.address.addressLine2}
/>
</label>
<label>
<DebounceInput
name="city"
placeholder="City"
debounceTimeout={300}
onChange={ (e) => this.handleChange(e, name)}
value={this.state.address.city}
/>
</label>
<label>
<br />
<DebounceInput
name="state"
placeholder="State"
debounceTimeout={300}
onChange={ (e) => this.handleChange(e, name)}
value={this.state.address.state}
/>
</label>
<label>
<DebounceInput
name="postalCode"
placeholder="Postal Code"
debounceTimeout={300}
onChange={ (e) => this.handleChange(e, name)}
value={this.state.address.postalCode}
/>
</label>
</form>
Maybe you can incorporate a condition inside of your handleChange function, where you check if your currentstate is sufficient to do a validation, if so you can trigger the validation.

Categories

Resources