I have the following model for my React (TypeScript) app:
interface IProjectInput {
id?: string;
name: string | i18n;
description: string | i18n;
}
export interface i18n {
[key: string]: string;
}
I am using Formik
and react-bootstrap
to create a new ProjectInput
from a Form
:
import { i18n as I18n, ... } from 'my-models';
interface State {
validated: boolean;
project: IProjectInput;
}
/**
* A Form that can can edit a project
*/
class ProjectForm extends Component<Props, State> {
constructor(props: any) {
super(props);
this.state = {
project: props.project || {
name: {},
description: ''
},
validated: false
};
}
async handleSubmit(values: FormikValues, actions: FormikHelpers<IProjectInput>) {
let project = new ProjectInput();
project = { ...project, ...values };
console.log("form values", values);
// actions.setSubmitting(true);
// try {
// await this.props.onSubmit(project);
// } catch (e) { }
// actions.setSubmitting(false);
}
render() {
const { t } = this.props;
const getCurrentLng = () => i18n.language || window.localStorage.i18nextLng || '';
const init = this.state.project || {
name: {},
description: ''
};
return (
<div>
<Formik
// validationSchema={ProjectInputSchema}
enableReinitialize={false}
onSubmit={(values, actions) => this.handleSubmit(values, actions)}
initialValues={init}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
errors,
isSubmitting,
setFieldTouched
}) => {
return (
<div className="project-form">
<Form noValidate onSubmit={handleSubmit}>
<Form.Row>
<Form.Group as={Col} md={{span: 5}} controlId="projectName">
<Form.Label>
{t('projectName')}
</Form.Label>
// Input for ENGLISH text
<Form.Control
type="text"
name="name"
value={(values['name'] as I18n).en}
onChange={handleChange}
/>
// Input for FRENCH text
<Form.Control
type="text"
name="name"
value={(values['name'] as I18n).fr}
onChange={handleChange}
/>
</Form.Group>
So in the end it should look like:
{
"name": {
"en": "yes",
"fr": "oui"
},
"description" : "test",
...
}
My problem is, that the value for the name
input stays empty.
I tried to add const init = this.state.project || { name: { 'en': '' },
in my render
or for my state
, but this did not do anything.
Formik has support for nested objects and arrays out of the box.
it is very simple just do console. log(formik. values) and you will get all the values without submitting it.
Initial field values of the form, Formik will make these values available to render methods component as values . Even if your form is empty by default, you must initialize all fields with initial values otherwise React will throw an error saying that you have changed an input from uncontrolled to controlled.
Change in your Form.Control
the prop name
to name.en
/name.fr
First of all, initialValues
is a prop that will be set and won't change unless you pass the prop enableReinitialize
. So it isn't good to do this.state.project || { name: { 'en': '' }
because it will only assume the first value of that, it can be this.state.project
or { name: { 'en': '' }
, but you will never know.
Second, to solve your problem, if you look at the docs about handleChange
:
General input change event handler. This will update the
values[key]
where key is the event-emitting input'sname
attribute. If thename
attribute is not present,handleChange
will look for an input'sid
attribute. Note: "input" here means all HTML inputs.
But in your Form.Control
you are passing the name
attribute as name="name"
.
So it's trying to update name
and not e.g. name.en
.
You should change
<Form.Control
type="text"
name="name"
value={(values['name'] as I18n).en}
onChange={handleChange}
/>
// Input for FRENCH text
<Form.Control
type="text"
name="name"
value={(values['name'] as I18n).fr}
onChange={handleChange}
/>
To
<Form.Control
type="text"
name="name.en" // correct name
value={(values['name'] as I18n).en}
onChange={handleChange}
/>
// Input for FRENCH text
<Form.Control
type="text"
name="name.fr" // correct name
value={(values['name'] as I18n).fr}
onChange={handleChange}
/>
Here is the docs that shows why you should use name.en
instead of just name
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With