I have a datepicker and it shows a default value(shows only if the api has a value), when I update it, onchange function doesn't give the selected value. it gives the initial value which is coming from the api. any idea how I can get the updated value to onchange function.
api data
const apidata = my api
setState({
...state,
formData:{
...apidata,
startDate:moment(apidata.startDate).utc()
}
})
form component
<Form
name="update form"
initialValues={state.formData}
autoComplete="off"
form={form}
>
<Form.Item
label="Start Date"
name="startDate"
rules={[{ required: true, message: "Please enter value!!!!!" }]}
>
<DatePicker
value={state.formData?.startDate}
onChange={(date: any)=>updateFields(date)}
/>
</Form.Item>
</Form>
update function
const updateFields = (data:any) => { // here I'm getting the already set api value not the changed value
setState({
...state,
formData : {
startDate:data
}
})
}
The bug is not easy to find if you don't share a minimal reproducible example.
If you use the defaultValue from antd Datepicker API the onChange works as expected.
<DatePicker
defaultValue={moment('2015-01-01', 'YYYY-MM-DD')}
onChange={updateFields}
/>
Here is a small stackblitz which works as expected using antd Datepicker and Form.Item.
E.g.:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Form, DatePicker } from 'antd';
import moment from 'moment';
const Demo = () => {
const [form] = Form.useForm();
function updateFields(date, dateString) {
console.log(date, dateString);
}
return (
<Form form={form} name="control-hooks">
<Form.Item name="DatePicker">
<DatePicker
defaultValue={moment('2015-01-01', 'YYYY-MM-DD')}
onChange={updateFields}
/>
</Form.Item>
</Form>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
Related
I am working on a React application and currently have a date picker to select a date range using Ant Design. I want to store the value of the selected date into a variable that can be accessed by another file in my program. How can I bind the selected value into a variable? Here is the JavaScript code for my date picker:
<p>Select a date range: </p>
</div>
<div className="left">
<Space direction="vertical" size={12}>
<RangePicker
format="YYYY-MM-DD"
onChange={this.onChange}
onOk={onOk}
/>
</Space>
Check the following example, You can store the date values in a variable once the date is selected and onChange function is called.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { DatePicker, Space } from 'antd';
import 'antd/dist/antd.css';
import './index.css';
const { RangePicker } = DatePicker;
const Demo = () => {
let selecteddate;
let selectedstartdate;
let selectedenddate;
const onChange = (value) => {
selecteddate = value;
selectedstartdate = value[0];
selectedenddate = value[1];
//Pass the following values
console.log("selecteddate:",selecteddate);
console.log("selectedstartdate:",selectedstartdate);
console.log("selectedenddate:",selectedenddate);
};
return (
<>
<p>Select a date range: </p>
<Space direction="vertical" size={12}>
<RangePicker format="YYYY-MM-DD" onChange={onChange} />
</Space>
</>
);
};
export default Demo
Screenshot
I'm working on a next.js (with typescript) project and I'm trying to build a form using react-hook-form. inside the form, I have a date picker created using react-multi-date-picker.
I tried the tutorial and the example code provided by the react-multi-date-picker documentation here
import React, { useState } from "react";
import DatePicker from "react-multi-date-picker";
import { useForm, Controller } from "react-hook-form";
export default function Example() {
const { control, handleSubmit } = useForm();
const [submittedDate, setSubmittedDate] = useState();
const onSubmit = ({ date }) => {
setSubmittedDate(date);
};
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="date"
rules={{ required: true }} //optional
render={({
field: { onChange, name, value },
fieldState: { invalid, isDirty }, //optional
formState: { errors }, //optional, but necessary if you want to show an error message
}) => (
<>
<DatePicker
value={value || ""}
onChange={(date) => {
onChange(date?.isValid ? date : "");
}}
format={language === "en" ? "MM/DD/YYYY" : "YYYY/MM/DD"}
/>
{errors && errors[name] && errors[name].type === "required" && (
//if you want to show an error message
<span>your error message !</span>
)}
</>
)}
/>
<input type="submit" />
</form>
<p>Submitted Date: {submittedDate?.format?.("MMMM D YYYY")}</p>
</>
)
}
but the code throws errors and doesn't work at all!
ReferenceError: language is not defined
if I delete the language, the error will go but the app doesn't work as expected.
so how can I get the value from the date picker using hook form?
I am new to react and I have just started using Formik
I like how simple it makes making forms and handling forms in react.
I have created multiple custom fields using formik, I am putting the react-select field I created as an example here.
import { ErrorMessage, Field } from "formik";
import React from "react";
import Select from 'react-select'
const SelectInput = (props) => {
const { label, name, id,options, required, ...rest } = props;
const defaultOptions = [
{label : `Select ${label}`,value : ''}
]
const selectedOptions = options ? [...defaultOptions,...options] : defaultOptions
return (
<div className="mt-3">
<label htmlFor={id ? id : name}>
{label} {required && <span className="text-rose-500">*</span>}
</label>
<Field
// className="w-full"
name={name}
id={id ? id : name}
>
{(props) => {
return (
<Select
options={selectedOptions}
onChange={(val) => {
props.form.setFieldValue(name, val ? val.value : null);
}}
onClick = {(e)=>{e.stopPropagation}}
{...rest}
// I want someting like onReset here
></Select>
);
}}
</Field>
<ErrorMessage
name={name}
component="div"
className="text-xs mt-1 text-rose-500"
/>
</div>
);
};
export default SelectInput;
This is the usual code I use for submitting form as you can see I am using resetForm() method that is provided by formik, I want to attach the reseting logic in on submit method itself.
const onSubmit = async (values, onSubmitProps) => {
try {
//send request to api
onSubmitProps.resetForm()
} catch (error) {
console.log(error.response.data);
}
};
If you want to reset the selected value after the form is submitted, you need to provide a controlled value for the Select component.
The Formik Field component provides the value in the props object, so you can use it.
For example:
SelectInput.js
import { ErrorMessage, Field } from 'formik';
import React from 'react';
import Select from 'react-select';
const SelectInput = ({ label, name, id, options, required, ...rest }) => {
const defaultOptions = [{ label: `Select ${label}`, value: '' }];
const selectedOptions = options ? [...defaultOptions, ...options] : defaultOptions;
return (
<div className='mt-3'>
<label htmlFor={id ? id : name}>
{label} {required && <span className='text-rose-500'>*</span>}
</label>
<Field
// className="w-full"
name={name}
id={id ? id : name}
>
{({
field: { value },
form: { setFieldValue },
}) => {
return (
<Select
{...rest}
options={selectedOptions}
onChange={(val) => setFieldValue(name, val ? val : null)}
onClick={(e) => e.stopPropagation()}
value={value}
/>
);
}}
</Field>
<ErrorMessage name={name} component='div' className='text-xs mt-1 text-rose-500' />
</div>
);
};
export default SelectInput;
and Form.js
import { Formik, Form } from 'formik';
import SelectInput from './SelectInput';
function App() {
return (
<Formik
initialValues={{
firstName: '',
}}
onSubmit={async (values, { resetForm }) => {
console.log({ values });
resetForm();
}}
>
<Form>
<SelectInput
name='firstName'
label='First Name'
options={[{ label: 'Sam', value: 'Sam' }]}
/>
<button type='submit'>Submit</button>
</Form>
</Formik>
);
}
export default App;
Therefore, if you click the Submit button, value in the Select component will be reset.
You can also make a useRef hook to the Fromik component and then reset the form within the reset function without adding it as a parameter to the function.
https://www.w3schools.com/react/react_useref.asp
It's one of the really nice hooks you'll learn as you progress through React :)
So if I understood you correctly you want to reset a specif field value onSubmit rather than resetting the whole form, that's exactly what you can achieve using actions.resetForm().
Note: If nextState is specified, Formik will set nextState.values as the new "initial state" and use the related values of nextState to update the form's initialValues as well as initialTouched, initialStatus, initialErrors. This is useful for altering the initial state (i.e. "base") of the form after changes have been made.
You can check this in more detail here.
And here is an example of resetting a specific field using resetForm() whereby you can see as you input name, email and upon submit only email field will get empty using resetForm.
import "./styles.css";
import React from "react";
import { Formik } from "formik";
const initialState = {
name: "",
email: ""
};
const App = () => (
<div>
<h1>My Form</h1>
<Formik
initialValues={initialState}
onSubmit={(values, actions) => {
console.log(values, "values");
actions.resetForm({
values: {
email: initialState.email
}
});
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
/>
<br />
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.email}
name="email"
/>
<br />
<br />
{props.errors.name && <div id="feedback">{props.errors.name}</div>}
<button type="submit">Submit</button>
</form>
)}
</Formik>
</div>
);
export default App;
I'm trying to split my code in more functions inside react functional components, so it's clearer to read and maintain the code, ie:
import React, { useEffect, useState } from "react";
import { StyledExchangeRateProvider } from "./styles";
import useUpdateRates from "../../hooks/useUpdateRates";
import {
FormControl,
InputLabel,
MenuItem,
Select,
TextField
} from "#material-ui/core";
export default function ExchangeRateProvider() {
// rates hook
const ratesContext = useUpdateRates();
const rates = ratesContext.state.rates;
// update rate on component did mount
useEffect(() => {
async function updateRates() {
if (!rates) {
await ratesContext.updateRate();
}
}
updateRates();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// save input values
const [values, setValues] = useState({
country: "VES",
amount: "",
total: ""
});
// change values
const handleChange = event => {
setValues({
...values,
[event.target.name]: event.target.value
});
};
function Amount() {
return (
<TextField
name="amount"
variant="filled"
label="Amount"
onChange={handleChange}
value={values.amount}
fullWidth
/>
);
}
function Country() {
return (
<FormControl fullWidth variant="filled" className="input">
<InputLabel id="Country">Country</InputLabel>
<Select
labelId="Country"
id="country"
name="country"
value={values.country}
onChange={handleChange}
>
<MenuItem value="ARS">Argentina</MenuItem>
<MenuItem value="BRL">Brazil</MenuItem>
<MenuItem value="INR">India</MenuItem>
<MenuItem value="VES">Venezuela</MenuItem>
<MenuItem value="ZAR">South Africa</MenuItem>
</Select>
</FormControl>
);
}
return (
<StyledExchangeRateProvider>
<Amount />
<Country />
</StyledExchangeRateProvider>
);
}
In this code, I'm separating in functions what I'll render in this component, so, ie, the Amount function returns a material-ui TextField. It will return more things, but for simplicity of this question, let's consider just this.
This code renders well, and all elements are shown. However, when I type something in the TextField, the cursor moves away from the TextField each caracter I type.
If I move the <TextField ... /> away from the Amount function and put it directly in the React Component return (switch the <Amount /> for <TextField ... />), the TextField works fine.
I've made a CodeSandBox with the behavior: https://codesandbox.io/s/dreamy-brattain-r4irj
My question is: why does it happen and how to fix it maintaining the code separated in functions?
Move Amount and Country Components outside of ExchangeRateProvider and pass data via props. The Issue is because on each render the functions are being recreated
i am developing a form in reactjs using formik plugin plugin link. when i submit form i am getting text fields values but dropdown values are coming empty...
this is my dropdown select
<div className="form-group">
<Field component="select" id="category" name="category" value={this.state.value} className={"form-control"} onChange={ this.handleChange }>
<option value="lokaler">Lokaler</option>
<option value="jobb">Jobb</option>
<option value="saker-ting">Saker & ting</option>
<option value="evenemang">Evenemang</option>
</Field>
</div>
handle submit function
export default withFormik({
enableReinitialize: true,
mapPropsToValues({ category }) {
return {
category: category || ''
}
},
handleSubmit(values, { setStatus, setErrors }){
console.log("data is this: ");
console.log(values); //here i am getting all form fields values except select value returning empty value
console.log("category: "+values.category);// here i always get empty value but not getting selected value
}
i am getting all text fields values in handle submit function but i am not able to get dropdown selected value....kindly tell me how to get dropdown select value in handle submit function ?
I also faced this problem yesterday. My problem was to submit form that contains ant design dropdown. I finally make it work after hours of:
revisiting the Formik Docs
watch Andrew Mead's video Better React Form with Formik again.
also viewing Jared Palmer's Working with 3rd-party inputs #1: react-select
The doc said you need to set onChange, onBlur events to setFieldValue, setFieldTouched props respectively like 3rd-party input example:
<MySelect
value={values.topics}
onChange={setFieldValue}
onBlur={setFieldTouched}
error={errors.topics}
touched={touched.topics}
/>
So to my problem, I need to change a bit:
<Select
{...field}
onChange={(value) => setFieldValue('fruitName', value)}
onBlur={()=> setFieldTouched('fruitName', true)}
value={values.fruitName}
...
>
...
</Select>
Hope this will help.
Here is my CodeSandbox
A more robust way to handle select components whilst using Formik would be to also use Jed Watsons react-select component. The two work together nicely and abstract away a lot of the boilerplate you would normally need to implement to get the component working seamlessly with Formik.
I have forked a simple example from Jared Palmer's react-select / Formik example on codesandbox and adjusted it to reflect your code above.
import "./formik-demo.css";
import React from "react";
import { render } from "react-dom";
import { withFormik } from "formik";
import Select from "react-select";
import "react-select/dist/react-select.css";
const options = [
{ value: "lokaler", label: "Lokaler" },
{ value: "jobb", label: "Jobb" },
{ value: "saker-ting", label: "Saker & ting" },
{ value: "evenemang", label: "Evenemang" }
];
const MyForm = props => {
const {
values,
handleChange,
handleBlur,
handleSubmit,
setFieldValue
} = props;
return (
<form onSubmit={handleSubmit}>
<label htmlFor="myText" style={{ display: "block" }}>
My Text Field
</label>
<input
id="myText"
placeholder="Enter some text"
value={values.myText}
onChange={handleChange}
onBlur={handleBlur}
/>
<MySelect value={values.option} onChange={setFieldValue} />
<button type="submit">Submit</button>
</form>
);
};
class MySelect extends React.Component {
handleChange = value => {
// this is going to call setFieldValue and manually update values.topcis
this.props.onChange("option", value);
};
render() {
return (
<div style={{ margin: "1rem 0" }}>
<label htmlFor="color">Select an Option </label>
<Select
id="color"
options={options}
onChange={this.handleChange}
value={this.props.value}
/>
</div>
);
}
}
const MyEnhancedForm = withFormik({
mapPropsToValues: props => ({
myText: "",
option: {}
}),
handleSubmit: (values, { setSubmitting }) => {
console.log(values);
}
})(MyForm);
const App = () => <MyEnhancedForm />;
render(<App />, document.getElementById("root"));
There are a few gotchas, you have to include the react select css for the component to display properly
import "react-select/dist/react-select.css";
the function mapPropsToValues option field should be initialised to an object
mapPropsToValues: props => ({
myText: "",
option: {}
Finally here is a link to the codesandbox example