How do I populate a form field with data from redux? - javascript

I am having trouble trying to dynamically populate my "client edit form" with data from the corresponding listing in my "client table". As you can see, I have tried using "{this.onChange}", but to no avail.
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import {
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
Card,
CardTitle,
CardText,
CardDeck,
CardSubtitle,
CardBody,
} from "reactstrap";
import { connect } from "react-redux";
import { getClients, addClient, deleteClient } from "../actions/clientActions";
import PropTypes from "prop-types";
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
state = {
detailModal: false,
editModal: false,
name: "",
email: "",
number: "",
};
toggleEdit = () => {
this.setState({
editModal: !this.state.editModal,
});
};
toggleDetails = () => {
this.setState({
detailModal: !this.state.detailModal,
});
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
renderClient = (clients, _id) => {
return (
<tr key={_id} timeout={500} classNames="fade">
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClick(clients._id)}
>
×
</Button>
<Button
style={{ marginLeft: ".2rem" }}
className="add-btn"
outline
color="warning"
size="sm"
onClick={this.toggleEdit}
>
Edit
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="detail-btn"
outline
color="info"
size="sm"
onClick={this.toggleDetails}
>
Details
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
render() {
const { clients } = this.props.client;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
<Modal isOpen={this.state.editModal} toggle={this.toggleEdit}>
<ModalHeader toggle={this.toggleEdit}> Edit Client </ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
placeholder="Add name"
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
placeholder="Add email"
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="number"
placeholder="Add number"
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Client Edit
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
<Modal isOpen={this.state.detailModal} toggle={this.toggleDetails}>
<ModalHeader toggle={this.toggleDetails}>
Client Details
</ModalHeader>
<CardDeck>
<Card></Card>
</CardDeck>
</Modal>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
How would I go about putting data from the redux store into the fields in my "Edit Client" form? If anyone has any ideas I would greatly appreciate it. This one is stumping me.

In general, by "controlling" the "value" property of an element. Instead of the element taking care of updating its displayed value natively - and triggering handlers only incidentally to what is visible - its value is passed in as the value from the store. The element then sets its value indirectly, through the reducer and store.
Clarification: the value of an html input element can be controlled using the jsx "value" prop. Pass in an onChange function (which you're already doing) and a value prop to create a typical controlled component.
<input value={state} onChange={onChange} />
https://reactjs.org/docs/forms.html#controlled-components

Related

React adding fields from a drop down menu

I'm fairly new to react, and I got involved in this project that was already ongoing, and I was asked to add more fields to a form, after the user chooses how many they want. Basically the form has a couple of fields, and if the user wants to add more people they can choose 1, 2, 3 or 4 and I need them to do so when choosing from a drop down menu, but I'm not sure how to do it. Can I make a div hide or not based on the click from the drop down? here is the code I'm working with.
It could also be one button that adds multiple fields on click one or the other
I've seen a couple of people doing it with redux, but I don't know enough of redux to figure out what they were doing.
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import {
Card, CardBody, Col, Button, Form, FormGroup, Label, Input, UncontrolledDropdown,
DropdownToggle, DropdownMenu, DropdownItem,
} from 'reactstrap';
import ChevronDownIcon from 'mdi-react/ChevronDownIcon';
import PropTypes from 'prop-types';
import StaticBar from './StaticBar';
import { getBasicQuote } from '../../../redux/actions/quoteActions';
import QuotePanel from './QuotePanel';
class VerticalForm extends PureComponent {
static propTypes = {
history: PropTypes.shape({}).isRequired,
getBasicQuotethis: PropTypes.func.isRequired,
};
constructor() {
super();
this.state = {
};
}
handleSubmit = async (event) => {
const { getBasicQuotethis } = this.props;
const gender = event.target.elements.gender.value;
const age = event.target.elements.age.value;
event.preventDefault();
getBasicQuotethis(age, gender);
}
render() {
return (
<>
<Col md={12} lg={12}>
<Card>
<CardBody>
<div className="card__title">
<h5 className="bold-text">Quote Tool</h5>
<h5 className="subhead">Labels are above fields</h5>
</div>
<Form className="form" onSubmit={this.handleSubmit}>
<FormGroup className="form__form-group">
<Label className="form__form-group-label" for="registerEmail">Gender</Label>
<Input
// className="form__form-group-field"
type="text"
name="gender"
id="registerEmail"
placeholder="Gender"
/>
</FormGroup>
<FormGroup className="form__form-group">
<Label className="form__form-group-label" for="registerPassword">Age</Label>
<Input
// className="form__form-group-field"
type="text"
name="age"
id="registerEmail"
placeholder="Age"
/>
</FormGroup>
<Button size="sm" className="btn btn-primary" type="Submit">
Submit
</Button>
<UncontrolledDropdown>
<DropdownToggle className="icon icon--right" outline color="primary">
<p>Add Dependent <ChevronDownIcon /></p>
</DropdownToggle>
<DropdownMenu className="dropdown__menu">
<DropdownItem>1</DropdownItem>
<DropdownItem>2</DropdownItem>
<DropdownItem>3</DropdownItem>
<DropdownItem divider />
<DropdownItem>4 +</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
</Form>
</CardBody>
</Card>
</Col>
<StaticBar />
<QuotePanel />
</>
);
}
}
export default connect(null, { getBasicQuotethis: getBasicQuote })(VerticalForm);
Thank you for your help
Ok so I figure it out how to do it.
class VerticalForm extends PureComponent {
static propTypes = {
history: PropTypes.shape({}).isRequired,
getBasicQuotethis: PropTypes.func.isRequired,
};
constructor() {
super();
this.state = {
showHideDependentSpouse: false,
showHideDependent2: false,
showHideDependent3: false,
showHideDependent4: false,
};
this.hideComponent = this.hideComponent.bind(this);
}
handleSubmit = async (event) => {
const { getBasicQuotethis } = this.props;
const gender = event.target.elements.gender.value;
const age = event.target.elements.age.value;
event.preventDefault();
getBasicQuotethis(age, gender);
}
hideComponent(name) {
switch (name) {
case 'showHideDependentSpouse':
this.setState(prevState => ({ showHideDependentSpouse: !prevState.showHideDependentSpouse }));
break;
case 'showHideDependent2':
this.setState(prevState => ({ showHideDependent2: !prevState.showHideDependent2 }));
break;
case 'showHideDependent3':
this.setState(prevState => ({ showHideDependent3: !prevState.showHideDependent3 }));
break;
case 'showHideDependent4':
this.setState(prevState => ({ showHideDependent4: !prevState.showHideDependent4 }));
break;
default:
}
}
render() {
const {
showHideDependentSpouse, showHideDependent2, showHideDependent3, showHideDependent4,
} = this.state;
return (
<>
<Col md={12} lg={12}>
<Card>
<CardBody>
<div className="card__title">
<h5 className="bold-text">Quote Tool</h5>
<h5 className="subhead">Labels are above fields</h5>
</div>
<Form className="form" onSubmit={this.handleSubmit}>
<FormGroup className="form__form-group">
<Label className="form__form-group-label" for="registerEmail">Gender</Label>
<Input
// className="form__form-group-field"
type="text"
name="gender"
id="registerEmail"
placeholder="Gender"
/>
</FormGroup>
<FormGroup className="form__form-group">
<Label className="form__form-group-label" for="registerPassword">Age</Label>
<Input
// className="form__form-group-field"
type="text"
name="age"
id="registerEmail"
placeholder="Age"
/>
<div>
{showHideDependentSpouse && <DependentSpouse />}
{showHideDependent2 && <Dependent1 />}
{showHideDependent3 && <Dependent1 />}
{showHideDependent4 && <Dependent4 />}
</div>
</FormGroup>
<Button size="sm" className="btn btn-primary" type="Submit">
Submit
</Button>
<Row>
<Col lg={8}>
<p>Check each box to add the respective number of dependents</p>
</Col>
<Col>
<Label check>
<Input type="checkbox" onClick={() => this.hideComponent('showHideDependentSpouse')} />
</Label>
</Col>
<Col>
<Label check>
<Input type="checkbox" onClick={() => this.hideComponent('showHideDependent2')} />
</Label>
</Col>
<Col>
<Label check>
<Input type="checkbox" onClick={() => this.hideComponent('showHideDependent3')} />
</Label>
</Col>
<Col>
<Label check>
<Input type="checkbox" onClick={() => this.hideComponent('showHideDependent4')} />
</Label>
</Col>
</Row>
</Form>
</CardBody>
</Card>
</Col>
<StaticBar />
<QuotePanel />
</>
);
}
}
export default connect(null, { getBasicQuotethis: getBasicQuote })(VerticalForm);
Basically set the state for each of the components i want to render, made individual components aside, and then made a logic to change the state false or true, then created a condition on each to check if the state is true.
Hopefully this will be helpful for someone.

How can I have a button in one component that renders another separate component?

I am trying to create an 'edit' button inside of component with an onClick that renders a separate component that is a 'client edit modal'. I'm having trouble figuring out how to do this.
Component with the 'edit' button
import React, { Component } from "react";
import { Table, Container, Button } from "reactstrap";
import {
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import {
getClients,
addClient,
editClient,
deleteClient,
} from "../actions/clientActions";
import PropTypes from "prop-types";
class ClientTable extends Component {
componentDidMount() {
this.props.getClients();
}
renderClient = (clients, _id) => {
return (
<tr key={_id} timeout={500} classNames="fade">
<td>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={() => this.onDeleteClick(clients._id)}
>
×
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="add-btn"
outline
color="warning"
size="sm"
>
Edit
</Button>
<Button
style={{ marginLeft: ".3rem" }}
className="detail-btn"
outline
color="info"
size="sm"
>
Details
</Button>
</td>
<td>{clients.name}</td>
<td>{clients.email}</td>
<td>{clients.number}</td>
</tr>
);
};
onDeleteClick = (id) => {
this.props.deleteClient(id);
};
render() {
const { clients } = this.props.client;
return (
<Container id="listContainer">
<Table
id="listTable"
className="table-striped table-bordered table-hover"
dark
>
<tr class="listRow">
<thead id="tableHeader">
<tr>
<th id="listActions">Actions</th>
<th id="listName">Name</th>
<th id="listEmail">Email</th>
<th id="listNumber">Number</th>
</tr>
</thead>
<tbody class="listRow">{clients.map(this.renderClient)}</tbody>
</tr>
</Table>
</Container>
);
}
}
ClientTable.propTypes = {
getClients: PropTypes.func.isRequired,
client: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, {
getClients,
deleteClient,
addClient,
})(ClientTable);
Component that button will render
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input,
} from "reactstrap";
import { connect } from "react-redux";
import { editClient } from "../actions/clientActions";
import { CLIENTS_LOADING } from "../actions/types";
class ClientEditModal extends Component {
state = {
modal: false,
name: "",
email: "",
number: "",
};
toggle = () => {
this.setState({
modal: !this.state.modal,
});
};
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = (e) => {
e.preventDefault();
const editClient = {
name: this.state.name,
email: this.state.email,
number: this.state.number,
};
this.props.editClient(editClient);
this.toggle();
};
render() {
return (
<div>
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}> Edit Client</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="name"> Name </Label>
<Input
type="text"
name="name"
id="client"
placeholder="Add name"
onChange={this.onChange}
></Input>
<Label for="email"> Email </Label>
<Input
type="text"
name="email"
id="client"
placeholder="Add email"
onChange={this.onChange}
></Input>
<Label for="number"> Number </Label>
<Input
type="text"
name="number"
id="client"
placeholder="Add number"
onChange={this.onChange}
></Input>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Submit Changes
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = (state) => ({
client: state.client,
});
export default connect(mapStateToProps, { editClient })(ClientEditModal);
I also would like to do the same for the 'details' button, but I assume that would be rather simple once I figure out how to do it once. If anyone has any ideas I would be very grateful! Thank you
You can do something like this:
class ClientEditModal extends Component {
//...
componentDidMount() {
if (this.props.isOpen) {
this.toggle(true);
}
}
toggle = (isOpen) => {
this.setState({
modal: isOpen,
});
}
// ...
}
and in your ClientTable, create a new state isOpen that you flip when you press the edit button.
showModal = () => {
this.setState({ isOpen: true; });
}
//...
<Button onClick={this.showModal}>Edit</Button>
Then pass the isOpen state to the ClientEditModal
<ClientEditModal isOpen={this.state.isOpen} {...otherProps} />

React with Antd Form onFinish not retrieve data

I'm a beginner in React and I was following a tutorial on how to create a React app with Django backend.In the video he uses Ant Design Components v3(that was the latest when the video was made). Now I'm using the latest one v4 and they changed the form onSubmit to onFinish. After some research in the comments, people posted about the update and how to make it work but no luck.The problem is that I'm trying to get the data from the form inputs(title and content) and it shows undefined.Any ideas?
Here is the component:
import React, { Component } from "react";
import { Form, Input, Button } from "antd";
const FormItem = Form.Item;
class CustomForm extends Component {
handleFormSubmit = (values) => {
const title = values.title;
const content = values.content;
console.log(title, content, values);
};
render() {
return (
<div>
<Form onFinish={(values) => this.handleFormSubmit(values)}>
<FormItem label="Title">
<Input name="title" placeholder="Article Content" />
</FormItem>
<FormItem label="Content">
<Input
name="content"
placeholder="Enter Article Content"
/>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit">
Submit
</Button>
</FormItem>
</Form>
</div>
);
}
}
export default CustomForm;
And the output of the console.log() is:
undefined, undefined, {}
It's because Form.Item or, in your case, FormItem, must have a name prop which is missing so values are not being saved against that key, so e.g.
Change this:
<FormItem label="Title">
<Input name="title" placeholder="Article Content" />
</FormItem>
To
<FormItem label="Title" name="title">
<Input placeholder="Article Content" />
</FormItem>
Here is what i use instead of onSubmit for antd 4.x.x Form:
import React from 'react';
import { Form, Input, Button } from 'antd';
const FormItem = Form.Item;
class CustomForm extends React.Component {
handleFormSubmit = (values) => {
const title = values.title;
const content = values.content;
console.log(title, content);
};
render(){
return (
<div>
<Form onFinish={(values) => this.handleFormSubmit(values)}>
<FormItem label="Title" name="title">
<Input placeholder="Put a title here" />
</FormItem>
<FormItem label="Content" name="content">
<Input placeholder="Enter some content ..." />
</FormItem>
<FormItem >
<Button type="primary" htmlType="submit">Submit</Button>
</FormItem>
</Form>
</div>
);
}
}
export default CustomForm;

React - Formik - Field Arrays - implementing repeatable form fields

I am trying to follow the Formik documentation on using FieldArrays so that I can add repeatable form elements to my form.
I've also seen this Medium post setting out an example.
I'm slow to learn and can't join the dots between the documentation and the implementation.
I want to have a button in my main form that says: "Add a request for data".
If that button is selected, then a nested form setting out the data profile is displayed, along with "add another data request" and "remove" buttons.
I have made the nested form in another component in my application, but I'm struggling to figure out how to use the example from the medium post to incorporate the nested form (as a repeatable element - ie someone might want 5 data requests).
Are there any examples of how to implement this?
In my code, I have basically followed the medium post, but tried to link the Data Request form component inside the index
<button
type="button"
onClick={() => arrayHelpers.insert(index, <DataRequestForm />)}>
Add a data request
</button>
This is plainly incorrect, but I can't get a handle on how to do this.
Taking Nithin's answer, I've tried to modify the embedded form so that I can use react-select, as follows, but I'm getting an error which says:
TypeError: Cannot read property 'values' of undefined
import React from "react";
import { Formik, Form, Field, FieldArray, ErrorMessage, withFormik } from "formik";
import Select from "react-select";
import {
Button,
Col,
FormControl,
FormGroup,
FormLabel,
InputGroup,
Table,
Row,
Container
} from "react-bootstrap";
const initialValues = {
dataType: "",
title: "",
description: '',
source: '',
}
class DataRequests extends React.Component {
render() {
const dataTypes = [
{ value: "primary", label: "Primary (raw) data sought" },
{ value: "secondary", label: "Secondary data sought"},
{ value: "either", label: "Either primary or secondary data sought"},
{ value: "both", label: "Both primary and secondary data sought"}
]
return(
<Formik
initialValues={initialValues}
render={({
form,
remove,
push,
errors,
status,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
dirty,
values
}) => {
return (
<div>
{form.values.dataRequests.map((_notneeded, index) => {
return (
<div key={index}>
<Table responsive>
<tbody>
<tr>
<td>
<div className="form-group">
<label htmlFor="dataRequestsTitle">Title</label>
<Field
name={`dataRequests.${index}.title`}
placeholder="Add a title"
className={"form-control"}
>
</Field>
</div>
</td>
</tr>
<tr>
<td>
<div className="form-group">
<label htmlFor="dataRequestsDescription">Description</label>
<Field
name={`dataRequests.${index}.description`}
component="textarea"
rows="10"
placeholder="Describe the data you're looking to use"
className={
"form-control"}
>
</Field>
</div>
</td>
</tr>
<tr>
<td>
<div className="form-group">
<label htmlFor="dataRequestsSource">Do you know who or what sort of entity may have this data?</label>
<Field
name={`dataRequests.${index}.source`}
component="textarea"
rows="10"
placeholder="Leave blank and skip ahead if you don't"
className={
"form-control"}
>
</Field>
</div>
</td>
</tr>
<tr>
<td>
<div className="form-group">
<label htmlFor="dataType">
Are you looking for primary (raw) data or secondary data?
</label>
<Select
key={`my_unique_select_keydataType`}
name={`dataRequests.${index}.source`}
className={
"react-select-container"
}
classNamePrefix="react-select"
value={values.dataTypes}
onChange={selectedOptions => {
// Setting field value - name of the field and values chosen.
setFieldValue("dataType", selectedOptions)}
}
onBlur={setFieldTouched}
options={dataTypes}
/>
</div>
</td>
</tr>
<tr>
<Button variant='outline-primary' size="sm" onClick={() => remove(index)}>
Remove
</Button>
</tr>
</tbody>
</Table>
</div>
);
})}
<Button
variant='primary' size="sm"
onClick={() => push({ requestField1: "", requestField2: "" })}
>
Add Data Request
</Button>
</div>
)
}
}
/>
);
};
};
export default DataRequests;
You cannot add nested forms inside a form element.
Please refer the below post for mode details.
Can you nest html forms?
If you are looking to nest multiple fields with a nested structure, inside a main form, you can achieve it using FieldArrays.
You can structure the form like.
{
firstName: "",
lastName: "",
dataRequests: []
}
Here firstName and lastName are top level form fields and dataRequests can be an array where each element follows the structure
{
requestField1: "",
requestField2: ""
}
Since dataRequests is an array, for rendering each item of FieldArray you need a map function.
form.values.dataRequests.map( render function() )
And for each rendered item, the change handlers should target their index to update the correct item in FieldArray.
<div key={index}>
<Field
name={`dataRequests.${index}.requestField1`}
placeholder="requestField1"
></Field>
<Field
name={`dataRequests.${index}.requestField2`}
placeholder="requestField2"
></Field>
<button type="button" onClick={() => remove(index)}>
Remove
</button>
</div>
In the above snippet name={dataRequests.${index}.requestField1} asks formik to update the key requestField1 of nth element of dataRequests array with the value of the input field.
Finally your <DataRequest /> component might look something like below.
import React from "react";
import { Field } from "formik";
export default ({ form, remove, push }) => {
return (
<div>
{form.values.dataRequests.map((_notneeded, index) => {
return (
<div key={index}>
<Field
name={`dataRequests.${index}.requestField1`}
placeholder="requestField1"
></Field>
<Field
name={`dataRequests.${index}.requestField2`}
placeholder="requestField2"
></Field>
<button type="button" onClick={() => remove(index)}>
Remove
</button>
</div>
);
})}
<button
type="button"
onClick={() => push({ requestField1: "", requestField2: "" })}
>
Add Data Request
</button>
</div>
);
};
And using <FieldArray /> you can connect <DataRequest /> to the main form.
You can try out the below sample SO snippet
function DataRequests({ form, remove, push }){
return (
<div>
{form.values.dataRequests.map((_notneeded, index) => {
return (
<div key={index}>
<Formik.Field
name={`dataRequests.${index}.requestField1`}
placeholder="requestField1"
></Formik.Field>
<Formik.Field
name={`dataRequests.${index}.requestField2`}
placeholder="requestField2"
></Formik.Field>
<button type="button" onClick={() => remove(index)}>
Remove
</button>
</div>
);
})}
<button
type="button"
onClick={() => push({ requestField1: "", requestField2: "" })}
>
Add Data Request
</button>
</div>
);
};
class Home extends React.Component {
initialValues = {
firstName: "",
lastName: "",
dataRequests: []
};
state = {};
render() {
return (
<div>
<Formik.Formik
initialValues={this.initialValues}
onSubmit={values => {
this.setState({ formData: values });
}}
>
{() => {
return (
<Formik.Form>
<div>
<Formik.Field
name="firstName"
placeholder="First Name"
></Formik.Field>
</div>
<div>
<Formik.Field
name="lastName"
placeholder="Last Name"
></Formik.Field>
</div>
<Formik.FieldArray name="dataRequests" component={DataRequests} />
<button type="submit">Submit</button>
</Formik.Form>
);
}}
</Formik.Formik>
{this.state.formData ? (
<code>{JSON.stringify(this.state.formData, null, 4)}</code>
) : null}
</div>
);
}
}
ReactDOM.render(<Home />, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/formik/dist/formik.umd.production.js"></script>
<div id="root"></div>
For anyone looking to learn from this post, the answer to this question from nithin is clearly motivated by good intentions, but it isn't a correct deployment of formik. You can check out a code sandbox here: https://codesandbox.io/embed/goofy-glade-lx65p?fontsize=14 for the current attempt at solving this problem (still not fixed) but a better step toward a solution. Thanks just the same for the helpful intentions behind the answer to this question.

Redux Forms for Creating and Editing

I am working with redux-form. I need to create a new user and update the user's information using the same form. I've made the required form to create a new user right now, but I don't know how to make it available for updating.
Form Component code:
class UserRegistrationForm extends PureComponent {
static propTypes = {
handleSubmit: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired,
isLoading: PropTypes.bool,
submitting: PropTypes.bool.isRequired,
};
constructor() {
super();
this.state = {
showPassword: false,
};
}
showPassword = (e) => {
e.preventDefault();
this.setState(prevState => ({ showPassword: !prevState.showPassword }));
};
onSubmit = data => {
console.log(data);
}
render() {
const { handleSubmit, reset } = this.props;
return (
<Col md={12} lg={12}>
<Card>
<CardBody>
<div className="card__title">
<h5 className="bold-text">STUDENT INFORMATION</h5>
</div>
<form className="form form--horizontal" onSubmit={handleSubmit}>
<div className="form__form-group">
<span className="form__form-group-label">First Name*</span>
<div className="form__form-group-field">
<Field
name="name"
component="input"
type="text"
placeholder="Name"
/>
</div>
</div>
<div className="form__form-group">
<span className="form__form-group-label">Last Name*</span>
<div className="form__form-group-field">
<Field
name="surname"
component="input"
type="text"
placeholder="Surname"
/>
</div>
</div>
<div className="form__form-group">
<span className="form__form-group-label">E-mail*</span>
<div className="form__form-group-field">
<Field
name="email"
component="input"
type="email"
placeholder="example#mail.com"
/>
</div>
</div>
<ButtonToolbar className="form__button-toolbar">
<Button color="primary" type="submit" className="icon" size="sm"><SendIcon /> Submit</Button>
<Button type="button" onClick={reset} className="icon" size="sm">
<CloseIcon /> Cancel
</Button>
</ButtonToolbar>
</form>
</CardBody>
</Card>
</Col>
);
}
}
export default reduxForm({
validate,
form: 'User_Registration_Form', // a unique identifier for this form
})(withTranslation('common')(UserRegistrationForm));
How can I make the form both available creating and updating?
To use the same form for the update as well, you would need to give an initialValues state to Form. Where initial values would be the value of the student you want to edit. Initialize values would be empty when you are creating a new student.
UserRegistrationForm = reduxForm({
validate,
form: 'User_Registration_Form', // a unique identifier for this form
})(withTranslation('common')(UserRegistrationForm));
InitializeFromStateForm = connect(
state => ({
initialValues: studentData
}),
)(InitializeFromStateForm)
export default UserRegistrationForm
An example is here https://redux-form.com/6.6.3/examples/initializefromstate/
Also in your react route file, try to maintain two routes with the same form component.
<Route path="/student/create" component={UserRegistrationForm} />
<Route path="/student/update/:id" component={UserRegistrationForm} />
So whenever you need to create, you redirect to create route and when you need to update, redirect it to update route, with an id as params.

Categories

Resources