React Formik Field onChange event handle - javascript

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>

Related

form.validateFields() doesnt work when we have custom antd form component

Considering the following example, this is stopping us to create custom components inside forms using antd4 version.
const handleFormSubmit = () => {
form
.validateFields()
.then((values: any) => {
console.log('success values => ', JSON.stringify(values));
successCallback(values);
})
.catch((errorInfo: any) => {
console.log('failureCallback values => ', JSON.stringify(errorInfo));
failureCallback(errorInfo);
});
};
<Form
form={form}
layout="vertical"
name="normal_login"
className="login-form"
initialValues={store.formData.initialValues}
>
<Form.Item>
<Input placeholder="Name" />
</Form.Item>
<Button type="primary" htmlType="submit" onClick={handleFormSubmit}>
Create
</Button>
</Form>
This works absolutely fine, whereas if the component is custom, then it doesn't work. Example:
function CustomInput(props){
return (
<Form.Item>
<Input placeholder={props.name} />
</Form.Item>
)
}
<Form
form={form}
layout="vertical"
name="normal_login"
className="login-form"
initialValues={store.formData.initialValues}
>
<CustomInput name="Name" />
Will display the field and also validates on change event. HandleFormSubmit is called, but it's not triggering success or failure block.
<Button type="primary" htmlType="submit" onClick={handleFormSubmit}>
Create
</Button>
</Form>
What's wrong here?
Try this instead of your Custom JSX
function CustomInput(props){
return (
<Form.Item name={props.name}> # Update this line only and remove this comment #
<Input placeholder={props.name} />
</Form.Item>
)
}
<Form
form={form}
layout="vertical"
name="normal_login"
className="login-form"
initialValues={store.formData.initialValues}
>
<CustomInput name="Name" />
<Button type="primary" htmlType="submit" onClick={handleFormSubmit}>
Create
</Button>
</Form>
NOTE: In Antd if your using Form.Item then you have to set name there
not on input fields. Form.Item assign its value to its Input.
I hope your doubt is solved comment for more views. I also tired of antd and wasted many days to understand this.

How to validate select input field using React Hook Form?

I'm trying to validate a form made using form fields from React MD by using React Hook Form. The text input fields are working fine.
But the validations aren't working on the select field. Here is the code:
<Controller
control={control}
name="salutation"
defaultValue=""
rules={{ required: "Salutation is required" }}
disabled={isSubmitting}
render={(props) => (
<Select
id="salutation"
{...props}
label="Salutation"
options={SALUTATION_ITEMS}
value={salutationValue}
onChange={(e) => handleSalutationChange(e)}
disableLeftAddon={false}
rightChildren={
<RiArrowDownSFill className="dropDownArrow" />
}
/>
);
}}
/>
The error persists even after the user selects a value:
{errors.salutation && (
<div className="validation-alert msg-error ">
<p>{errors.salutation.message}</p>
</div>
)}
I'm probably missing something or doing something wrong.
I think you are missing props.value and props.onChange(e) and you may not need handleSalutationChange(e):
<Controller
control={control}
name="salutation"
defaultValue=""
rules={{ required: "Salutation is required" }}
disabled={isSubmitting}
render={(props) => (
<Select
id="salutation"
{...props}
label="Salutation"
options={SALUTATION_ITEMS}
value={props.value} // This one: props.value
onChange={(e) => {
props.onChange(e) // I think you are missing this
handleSalutationChange(e) // NOT Needed ?
}}
disableLeftAddon={false}
rightChildren={
<RiArrowDownSFill className="dropDownArrow" />
}
/>
);
}}
/>

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]
})
}

How to make a 'Select' component as required in Material UI (React JS)

I want to display like an error with red color unless there is a selected option.
Is there any way to do it.
For setting a required Select field with Material UI, you can do:
class SimpleSelect extends React.PureComponent {
state = {
selected: null,
hasError: false
}
handleChange(value) {
this.setState({ selected: value });
}
handleClick() {
this.setState(state => ({ hasError: !state.selected }));
}
render() {
const { classes } = this.props;
const { selected, hasError } = this.state;
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl} error={hasError}>
<InputLabel htmlFor="name">
Name
</InputLabel>
<Select
name="name"
value={selected}
onChange={event => this.handleChange(event.target.value)}
input={<Input id="name" />}
>
<MenuItem value="hai">Hai</MenuItem>
<MenuItem value="olivier">Olivier</MenuItem>
<MenuItem value="kevin">Kevin</MenuItem>
</Select>
{hasError && <FormHelperText>This is required!</FormHelperText>}
</FormControl>
<button type="button" onClick={() => this.handleClick()}>
Submit
</button>
</form>
);
}
}
Working Demo on CodeSandBox
Material UI has other types of Select(native) also where you can just use plain HTML required attribute to mark the element as required.
<FormControl className={classes.formControl} required>
<InputLabel htmlFor="name">Name</InputLabel>
<Select
native
required
value={this.state.name}
onChange={this.handleChange}
inputProps={{
name: 'name',
id: 'name'
}}
>
<option value="" />
<option value={"lala"}>lala</option>
<option value={"lolo"}>lolo</option>
</Select>
</FormControl>
P.S. https://material-ui.com/demos/selects/#native-select
The required prop only works when you wrap your elements inside a <form> element, and you used the submit event to submit the form.
this is not related to react, this is pure HTML.
In MUI v5 (2022), it works like this:
const handleSubmit = (e)=>{
e.preventDefault()
// ...
}
return (
<form onSubmit={handleSubmit}>
<Select required value={val} onChange={handleChange} required>
<MenuItem value="yes">Yes</MenuItem>
<MenuItem value="no">No</MenuItem>
</Select>
<Button type="submit">Submit</Button>
</form>
)
As you can see, it works the same way you think it should work, so what your code should probably be similar to this.
But the required prop only works when you wrap your elements inside a element, and you used the submit event to submit the form.
And if you're using <FormControl>, but the required prop on both elements:
<FormControl required>
<Select required>
// ...
</FormControl>

Reactjs redux-form fields - custom checkbox/radiobox component - bug in initial checked

I am working on a custom radiobutton/checkbox component -- based off the renderField. The component appears to render fine, but when I've added a "checked" parameter to this it breaks. The field is selected correctly - but when toggling options it looks like it tries to force check the old item.
//renderField
import React from 'react'
const renderField = ({input, label, type, meta: {touched, error, warning}}) => (
<div className='field'>
<label>
{touched &&
<span>
{label}
</span>
}
{touched &&
((
error &&
<span className="error">
: {error}
</span>) ||
(
warning &&
<span className="warning">
: {warning}
</span>
))}
</label>
<div>
<input {...input} placeholder={label} type={type} />
</div>
</div>
)
export default renderField
here is the new field -- the markup is different to the standard input fields.
//renderRadioCheckField
import React from 'react'
import _ from 'underscore';
function renderRadioCheckField({input, label, type, checked, meta: {touched, error, warning}}) {
const randId = _.uniqueId('radiocheck_');
return (
<div className='field'>
<div>
<input {...input} placeholder={label} type={type} id={randId} checked={checked} />
<label className="group-label" htmlFor={randId}>
{label}
</label>
</div>
</div>
);
}
export default renderRadioCheckField
--
on my form component I am importing these in and calling them as such
<Field name="test" type="text" component={renderField} label="test" />
<br/><br/>
<Field name="radio-group1" type="radio" component={renderRadioCheckField} value="check1" label="Apple2" />
<Field name="radio-group1" type="radio" component={renderRadioCheckField} value="check2" label="Peach2" checked="true" />
<Field name="radio-group1" type="radio" component={renderRadioCheckField} value="check3" label="Orange2" />
<br/><br/>
<Field name="check-group1" type="checkbox" component={renderRadioCheckField} value="check1" label="Yes" />
<Field name="check-group1" type="checkbox" component={renderRadioCheckField} value="check2" label="No" checked="true" />
Don't use the checked="true". Instead do following in your componentDidMount() method of React Redux Form component.
componentDidMount(){
const {radio-group1} = this.props;
//Sets initial default checked value
this.props.change('radio-group1','check2');
}
You can do same for checkboxes.

Categories

Resources