Formik - TextField does not accept numeric value when using react-number-format - formik

I'm using react-number-format library if numeric values is set to TextField it will not show any error after reset the form.
t should accept the numeric values also like other string values.
Here is my code you are reproduce error from this.
Formik Form
<Formik
enableReinitialize
initialValues={{
area: "",
password: "",
}}
validate={(values) => {
const errors: Partial<Values> = {};
if (!values.area) {
errors.area = "Required area";
}
return errors;
}}
onSubmit={(values, { setSubmitting, resetForm }) => {
setTimeout(() => {
setSubmitting(false);
console.log(JSON.stringify(values, null, 2));
resetForm();
}, 500);
}}
>
{({ submitForm, isSubmitting }) => (
<Form>
<Field
component={TextField}
name="area"
label="area"
InputProps={{
inputComponent: NumberField,
}}
/>
<br />
<Field
component={TextField}
type="password"
label="Password"
name="password"
/>
{isSubmitting && <LinearProgress />}
<br />
<Button
variant="contained"
color="primary"
disabled={isSubmitting}
onClick={submitForm}
>
Submit
</Button>
</Form>
)}
</Formik>
NumberField
import NumberFormat from "react-number-format";
interface NumberFieldProps {
name: string;
inputRef: (instance: NumberFormat<any> | null) => void;
onChange: (event: {
target: { name: string; value: number | undefined };
}) => void;
}
export default function NumberField(props: NumberFieldProps) {
const { inputRef, onChange, ...other } = props;
return (
<NumberFormat
{...other}
getInputRef={inputRef}
onValueChange={(values) => {
onChange({
target: {
name: other.name,
value: values.floatValue,
},
});
}}
/>
);
}
Click on submit button and you will see Required area error, Set value in area field and submit form, it submit the form and reset it after that click again on submit button you will see it will not give you Required area error. I don't know why this happen.
Now change value: values.floatValue to value: values.value in NumberField file and everything work well. I don't know why it is not working when I set floatValue I need numeric values not string.

Related

Formik does not update value from input

I am trying to add Form to my application, so I decided to pick formik and I ran into a little problem
I have following components:
After typing something in input, I am clicking submit and alert appears with empty data like:
{
someName: ''
}
Why someName does not update?
const SearchInput = ({name, ...props}) => {
const [field] = useField(name);
return (
<Styled.Wrapper>
<Styled.Input {...field} {...props} placeholder="Search" />
</Styled.Wrapper>
);
};
const Form = () => {
return (
<Formik
initialValues={{
someName: '',
}}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
>
{(props: FormikProps<Values>) => (
<FormikForm>
<SearchInput
name="someName"
type="text"
label="Some Name"
onChange={props.handleChange}
value={props.values.jobName}
/>
<button type="submit">Submit</button>
</FormikForm>
)}
</Formik>
)
};
export default Form;

Change the options passed to formik (Field) form after selecting the value from other dropdown

Below is the code which I am using. When I am changing the data for Division the state of district list is changed but it is not shown in the form. I need to click on the form and the changed state data is reflected. I want it to get reflected once the state is changed.
function Input(props) {
const { label, name, ...rest } = props
return (
<div>
{/* <label htmlFor={name}>{label}</label> */}
<Field id={name} name={name} {...rest} />
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Select(props) {
const { label, name, options, ...rest } = props
return (
<div className="form-group">
{/* <label htmlFor={name}>{label}</label> */}
<Field as='select' id={name} name={name} {...rest} >
{
options.map(option => {
return(
<option key={option.value} value={option.value}>
{option.key}
</option>
)
})
}
</Field>
<ErrorMessage name={name} component={TextError}/>
</div>
)
}
function Test() {
const [divisions, setDivisions] = useState([])
const [districts, setDistricts] =useState([])
const [blocks, setBlocks] = useState([])
const [initialValues,setInitialValues] = useState({
divisionCode:"",
districtCode:"",
blockCode : "",
name : "",
})
const validationSchema = Yup.object({
divisionCode :Yup.string().required('Required!!'),
districtCode :Yup.string().required('Required!!'),
blockCode : Yup.string().required('Required!!'),
name : Yup.string().required('Required!!'),
})
async function getDivisionList() {
try {
const res = await axios.get("APIURL")
return (res.data.response)
} catch (error) {
console.error(error);
}
}
function getDistrictList(divisionCode) {
axios.get("APIURL")
.then(res=>{
setDistricts(res.data.response)
return res.data.response[0].value
})
}
function getBlockList(districtCode) {
axios.get("APIURL")
.then(res => {
setBlocks(res.data.response)
})
}
useEffect(() => {
getDivisionList().then(res => {
setDivisions(res)
});
}, [])
const onSubmit = values => {
console.log('Form data ',values)
console.log('Saved data ',JSON.parse(JSON.stringify(values)))
}
return (
<Formik
initialValues = {initialValues}
validationSchema = {validationSchema}
onSubmit = {onSubmit}
>
{
formik => <Form>
<Select control='select' label='Division' onBlur={e => { var data = getDistrictList(e.currentTarget.value)}} name='divisionCode' options={divisions} />
<Select control='select' label='District' onBlur={e => { getBlockList(e.currentTarget.value)}} name='districtCode' options={districts} />
<Select control='select' label='Block' name='blockCode' options={blocks} />
<Input control='input' type='text' label='Name' name='name' />
<button type="submit" disabled={!formik.isValid}>Submit</button>
</Form>
}
</Formik>
)
}
export default Test
Thanks in Advance. It will be very helpful.

react hook, validate Form with reduxForm

I Have external component managing my input Field and throws an error if no input is made.
On submit of form previously with class component along with reduxForm effect, this would throw an error of missing input, am wondering how to achieve this with hooks since submission passes whether i have input or Not.
import ConstructField from '../components.render';
const ActivitiesForm = () => {
const handleSubmit_ = () => {
console.log({ activityName });
};
const [activityName, setActivityName] = useState(null);
const handleInputName = (e) => setActivityName(e.target.value);
const { items } = useSelector((state) => ({
items: state.items,
}));
const { register, handleSubmit, errors, control } = useForm();
return (
<div>
<Form onSubmit={handleSubmit(handleSubmit_)} className='ui form'>
<Form.Group widths='equal'>
<Field
component={ConstructField('input')}
onChange={handleInputName}
label='Activity Name'
name='activityName'
placeholder='Activity Name'
validate={required}
/>
</Form.Group>
<br />
<Form.Group inline>
<Button.Group>
<Button primary>Save</Button>
<Button.Or />
<Button positive onClick={goBackButton}>
Go Back
</Button>
</Button.Group>
</Form.Group>
</Form>
</div>
);
};
const required = (value) => (value ? undefined : 'this field is required');
const activityform = reduxForm({
form: 'activityform',
enableReinitialize: true,
})(ActivitiesForm);
export default activityform;

React Redux Material-UI autocomplete

I am struggling to get the value out of the Material-ui Autocomplete when using redux-form. Has anyone solved this? I am using the exact example from the material-ui Autocomplete https://material-ui.com/components/autocomplete/ I am able to see the list options and it populates after clicking it twice, but I am unable to extract the real value, instead I am returning ({ title : 0 }) instead of the value.
import React from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { Field, reduxForm } from "redux-form";
import { connect } from "react-redux";
class Form extends React.Component {
onSubmit = formValues => {
console.log(formValues);
};
renderTextField = ({
label,
input,
meta: { touched, invalid, error },
...custom
}) => (
<Autocomplete
label={label}
options={this.props.movies}
placeholder={label}
getOptionLabel={option => option.title}
onChange={input.onChange}
{...input}
{...custom}
renderInput={params => (
<TextField {...params} label={label} variant="outlined" fullWidth />
)}
/>
);
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.onSubmit)}>
<Field
name="propertySelector"
component={this.renderTextField}
label="Select Property"
type="text"
/>
</form>
</div>
);
}
}
const mapStateToProps = state => {
console.log(state);
return {
movies: [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
{ title: "Schindler's List", year: 1993 }
]
};
};
Form = reduxForm({
form: "auto_complete"
});
export default connect(mapStateToProps, null)(Form);
Solved by passing in the (event, value) to the onChange props.
onChange={(event, value) => console.log(value)}
From the docs;
Callback fired when the value changes.
Signature:
function(event: object, value: T) => void
event: The event source of the callback.
value: null

I am using antd deign to show select option but select cant read id provided and also cannot update onChange

I am using antd deign to show select option but select cant read id provided and also cannot update onChange.
import React from "react";
const data = {
orgName: "",
orgRegNo: "",
orgType: "",
orgTypes: [
{ id: "1", name: "Vendor" },
{ id: "2", name: "Supplier" },
{ id: "3", name: "Vendor and Supplier" }
]
};
export const MyContextTSX = React.createContext(data);
const Store = (props: any) => {
return (
<MyContextTSX.Provider value={data}>{props.children}</MyContextTSX.Provider>
);
};
export default Store;
//Next page of React signup
const signinData = useContext(MyContextTSX);
const [values, setValues] = useState(signinData);
<Select
id={values.orgTypes.id} //shows error while showing id
// name={values.orgTypes.name}
defaultValue="Choose"
style={{ width: 150 }}
onChange={(value: any) => //cant perform onChange
setValues({ ...value, name: value })
}
>
{values.orgTypes.map((option: any) => (
<Option
key={option.id}
value={option.name}
// onChange={handleChange}
>
{option.name}
</Option>
))}
</Select>
I am using antd deign to show select option but select cant read id provided and also cannot update onChange.
Link to CodeSandbox
There are few issues in your code.
Firstly, you are trying to access id from orgTypes which is an array. Instead you can defined a normal id.
Secondly, You need to have a contextProvider wrapping your App component
Third. You need to update state in the correct format such that you are not updating the data but the selected value. For that you need to have a state for selected value
Relavant code
index.js
ReactDOM(
<Store>
<App />
</Store>,
document.getElementById("root")
);
useForm.js
import { useContext, useState } from "react";
import { MyContextTSX } from "./Store";
const useForm = ({ callback }) => {
const values = useContext(MyContextTSX);
const [selected, setSelected] = useState({});
return { values, selected, setSelected };
};
export default useForm;
Register.js
const Register = () => {
const { values, selected, setSelected } = useForm({});
return (
<React.Fragment>
<Select
id={"select"} //shows error here
defaultValue="Choose"
style={{ width: 150 }}
onChange={(
value: any //what to do here ?
) => setSelected(selected)} //what to do here ?
>
{values.orgTypes.map((option: any) => (
<Option key={option.id} value={option.name}>
{option.name}
</Option>
))}
</Select>
<button onClick={() => console.log(values.orgTypes)}>Test</button>
</React.Fragment>
);
};
There are many problems with your code:
id={values.orgTypes.id} // orgTypes is an array, use values.orgTypes[0].id
---
onChange={(
value: any // value is the Select.Option value
) => setValues({ ...value, name: value })} // What exatcly you trying to do here?
Moreover, you don't specify types (and using Typescript).
Check this working example (Javascript):
const data = {
orgName: '',
orgRegNo: '',
orgType: '',
orgTypes: [
{ id: '1', name: 'Vendor' },
{ id: '2', name: 'Supplier' },
{ id: '3', name: 'Vendor and Supplier' }
]
};
const MyContextTSX = React.createContext(data);
function Signup() {
const signinData = useContext(MyContextTSX);
const [selected, setSelected] = useState();
return (
<div>
<h1>Selected: {selected}</h1>
<Select
defaultValue="Choose"
style={{ width: 150 }}
onChange={value => setSelected(value)}
>
{signinData.orgTypes.map(option => (
<Select.Option key={option.id} value={option.name}>
{option.name}
</Select.Option>
))}
</Select>
</div>
);
}
Demo:
Tweaking little bit #Dennish Vash answer and the signup function can also be written like this
function Signup() {
const signinData = useContext(MyContextTSX);
const [selected, setSelected] = useState();
return (
<div>
<h1>Selected: {selected}</h1>
<Select
defaultValue="Choose"
style={{ width: 150 }}
onChange={value => setSelected(value)}
>
{signinData.orgTypes.map(option => (
<Option value="{option.id}">{option.name}</Option>
))}
</Select>
</div>
);
}
Reference: https://github.dev/ant-design/ant-design/tree/master/components/select/demo

Resources