sending info from react-select into a handleSubmit function - javascript

I receive some info from an API and show them as react-select drop-down items. I want to choose any item and then delete it by pressing a button, which sends the value to my handleSubmit function to be sent to the API again:
export class DeleteDepModal extends Component {
state = {
departments: [],
idValue: ' '
}
getDepartments() {
axios.get('/api/jobs/list-departments',{headers:headers}).then(resp=>{
this.setState({
departments: resp.data.map(departments=>({label:[departments.name,' ',departments.company_name], value:departments.id})),
})
})
}
componentDidMount() {
this.getDepartments()
}
handleSubmit = (event) => {
event.preventDefault()
console.log('handleDeletesubmitshot')
const DepID = this.state.idValue
axios(
{
method: 'delete',
url: '/api/jobs/delete-department' + DepID,
headers: headers,
})
.then(response => {
console.log(response)
alert('Department Deleted Successfully!')
})
.then(
this.getDepartments()
)
.catch(error => {
console.log(error.response)
})
}
render () {
return (
<Modal
{...this.props}
size='lg'
aria-labelledby='contained-modal-title-vcenter'
centered
>
<Modal.Header closeButton>
<Modal.Title style={{ color: 'black' }} id='contained-modal-title-vcenter'>
Delete Department
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className='container'>
<Form onSubmit={this.handleSubmit}>
{
<Row>
<Col xs={6}>
<Select onChange={(event) => this.setState({ idValue: event.target.departments[i].value})} placeholder='Select from pre-created Departments' required options={this.state.departments}/>
</Col>
<Col xs={6}>
<Button style={{ position: 'relative', left: '150px' }} variant='danger' type='submit'>Delete Department</Button>
</Col>
</Row>
}
</Form>
</div>
</Modal.Body>
<Modal.Footer />
</Modal>
)
}
}
departments[i].value is the info I want to send to my handleSubmit function, but now I have 2 problems:
I don't know how to iterate in my department's array and get the index of the item that is selected (i), a for loop doesn't work
event.target is unidentified and doesn't get the info to the handleSubmit function
What should I do?

With react select's onChange, you will get the value in the callback (not event). Also you don't need to iterate department array and get the index.
Below code should suffice
<Select
onChange={(value) =>
this.setState({
idValue: value,
})
}
placeholder="Select from pre-created Departments"
required
options={this.state.departments}
/>

Related

How to get the collapse to open depending if there is an error - ReactJs

Hi all I have following code.
I have two inputs and that two inputs are mandatory.
First input name is Name and when I am submit with any values it says Please input Name! . This part was working great.
Second input, which name is Short Info was located in collapse. And that collapse is <Form.Item>, it's mean that user can press + and add multiple Short Info inputs.
My problem is with that Short Info. When user press submit only first input shows error. For Short Info user should open that collapse to see error, which is not good.
Now how can I automatically open that collapse panel if there is error ?
Here is my code.
const [dataFromBackend, setDataFromBackend] = useState([]);
const addNewField = () => {
setDataFromBackend([...dataFromBackend]);
};
const submitForm = (values) => {
console.log('Received values of form: ', values);
};
const Header = ({ remove, index }) => {
return (
<Col align="center" span={1} justify="end">
<MinusCircleFilled
onClick={(e) => {
e.stopPropagation();
remove(index);
}}
/>
</Col>
);
};
return (
<>
<Form
name="validate_other"
onFinish={submitForm}
initialValues={{ values: [''] }}
>
<Form.Item
name="name"
label="Name"
rules={[
{
required: true,
message: 'Please input Name!',
},
]}
>
<Input />
</Form.Item>
<Form.List name="values">
{(fields, { add, remove }) => {
return (
<Row gutter={24}>
<Col span={24} md={24}>
<Card
title="Price"
extra={
<PlusCircleFilled
style={{
cursor: 'pointer',
fontSize: '20px',
color: '#00AEE6',
}}
onClick={() => {
add();
addNewField();
}}
/>
}
>
<div key={fields.key}>
{fields.map((field, i) => (
<div key={i}>
<Collapse accordion={true}>
<Panel
key={i}
header={<Header remove={remove} index={i} />}
>
<Col span={24} md={24}>
<Form.Item
name={[field.name, 'shortinfo']}
fieldKey={[field.fieldKey, 'shortinfo']}
label={'Short Info'}
rules={[
{
required: true,
message: 'Please input short info!',
},
]}
>
<Input />
</Form.Item>
</Col>
</Panel>
</Collapse>
</div>
))}
</div>
</Card>
</Col>
</Row>
);
}}
</Form.List>
<Button htmlType="submit">Save</Button>
</Form>
</>
)
Please help me to resolve this problem, thanks.
My solution would be as follows:
First of all, render all <Panels> inside the same <Colapse>, also remove accordion={true} from Colapse (so multiple Fields can be open at once) and add forceRender={true} to Panels, otherwise items inside a Panel are lazy loaded (if lazy load would be active, <Form.Item> wouldn't be rendered and don't show up as error)
<Collapse>
{fields.map((field, i) => {
return (
<Panel
...
forceRender={true}
...
>
...
</Panel>
);
})}
</Colapse>
Add a state to keep track of currently active keys and add it to the colapse, also remove the <div key={i}> it is not needed, since <Panel key={i}> is already a container, furthermore it will prevent onChange of Colapse to trigger and mess up your styling
const [activeKeysColapse, setactiveKeysColapse] = useState([]);
...
<Collapse
activeKey={activeKeysColapse}
onChange={(newActiveKeys) => {
// otherwise panels couldn't be open/closed by click
setactiveKeysColapse(newActiveKeys);
}}
>
{fields.map((field, i) => {
return (
<Panel
key={i}
forceRender={true}
>
...
</Panel>
);
})}
</Colapse>
Add onFinishFailed listener to form
const submitFormFailed = (errors) => {
// get all errorFields from the list and map the
// `activeKeys` to the index (because `<Panel key={i}>`)
const newShortInfoErrors = errors.errorFields
.filter((el) => el.name[0] === 'values')
.map((el) => el.name[1].toString());
// setting the state will close all fields which
// are valid and open all with an error message
setactiveKeysColapse(newShortInfoErrors);
};
...
<Form
...
onFinishFail={submitFormFailed}
>
Based on the code on your StackBlitz, this will do exactly what you want
I hope this will solve your problem, if there is anything unclear, feel free to comment

How to use Formik with dynamicly generated lists (e.g. via AJAX or setState)?

I have a dynamic array of form fields, whose values are fetched via REST API. On the page, there is also a dropdown, that, when changed, shows a different array of fields. I fetch all of these fields/values during the componentDidMount life cycle hook and filter the list to show the relevant data.
The Formik docs mention FieldArrays as a means to handle an array of fields. However, their example shows a static list of objects as its initialValues -- but I don't see how dynamically generated lists. In fact, since I'm fetching initialValues via AJAX, it's initially an empty array -- so nothing is rendered even after getting the data.
This is simplified version of my code:
const MyComponent = class extends Component {
componentDidMount() {
// data structure: [{Name: '', Id: '', Foo: '', Bar: ''}, ...]
axios
.get('/user')
.then((res) => {
this.setState({
userData: res.data
});
});
}
render() {
return (
<div>
<Formik
initialValues={{
users: this.state.userData
}}
render={({values}) => (
<Form>
<FieldArray
name="users"
render={arrayHelpers => (
<ul>
{
values.users.map((user, index) => {
return (
<li key={user.Id}>
<div>{user.Name}</div>
<Field name={`user[${index}].Foo`} type="text" defaultValue={user.Foo} />
<Field name={`user[${index}].Bar`} type="text" defaultValue={user.Bar} />
</li>);
}
}
</ul>
)}
/>
</Form>
)}
/>
</div>
);
}
}
You can do this via setting enableReinitialize true. According to doc it will do this:
Default is false. Control whether Formik should reset the form if initialValues changes (using deep equality).
I created complete codesanbox where your incoming data is async and when you push the data its also async. check this:
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { Formik, Field, Form, ErrorMessage, FieldArray } from "formik";
const InviteFriends = () => {
const [initialValues, setInitialValues] = React.useState({
friends: []
});
useEffect(() => {
const initialValues = {
friends: [
{
name: "",
email: ""
}
]
};
const timer = setTimeout(() => {
setInitialValues(initialValues);
}, 1000);
return () => {
timer && clearTimeout(timer);
};
}, []);
return (
<div>
<h1>Invite friends</h1>
<Formik
initialValues={initialValues}
enableReinitialize={true}
onSubmit={async (values) => {
await new Promise((r) => setTimeout(r, 500));
alert(JSON.stringify(values, null, 2));
}}
>
{({ values }) => (
<Form>
<FieldArray name="friends">
{({ insert, remove, push }) => (
<div>
{console.log("Values", values, initialValues)}
{values.friends.length > 0 &&
values.friends.map((friend, index) => (
<div className="row" key={index}>
<div className="col">
<label htmlFor={`friends.${index}.name`}>Name</label>
<Field
name={`friends.${index}.name`}
placeholder="Jane Doe"
type="text"
/>
<ErrorMessage
name={`friends.${index}.name`}
component="div"
className="field-error"
/>
</div>
<div className="col">
<label htmlFor={`friends.${index}.email`}>
Email
</label>
<Field
name={`friends.${index}.email`}
placeholder="jane#acme.com"
type="email"
/>
<ErrorMessage
name={`friends.${index}.name`}
component="div"
className="field-error"
/>
</div>
<div className="col">
<button
type="button"
className="secondary"
onClick={() => remove(index)}
>
X
</button>
</div>
</div>
))}
<button
type="button"
className="secondary"
onClick={async () => {
await new Promise((r) =>
setTimeout(() => {
push({ name: "", email: "" });
r();
}, 500)
);
}}
>
Add Friend
</button>
</div>
)}
</FieldArray>
<button type="submit">Invite</button>
</Form>
)}
</Formik>
</div>
);
};
ReactDOM.render(<InviteFriends />, document.getElementById("root"));
Here is the demo: https://codesandbox.io/s/react-formik-async-l2cc5?file=/index.js

how do you single select change the value when the radio button is checked, using react hooks?

there are two questionnaire list cards, each of which has a questionnaire_id and several question_choice_id, when the radio button is selected, it can only select one question_choice_id based on the quisioner_id, how to add the quisioner_id
and question_choice_id into a state on react hooks?
so this assumption will be like this
choice_id: [1,1], question_id: [2,4]
handleSelected function
const handleSelected = (choiceId, questionId) => {
setQuestion(questionId)
setChoice(choiceId)
console.log(questionId, choiceId)
}
handleSubmit function
const handleSubmit = (e) => {
const choice_id = choiceId
const question_id = questionId
const quisioner = {
choice_id,
question_id
}
e.preventDefault()
api.post('api/questionnaire/response', quisioner, { headers: { 'Authorization': JSON.parse(storage.getItem('token')) } })
.then(res => {
console.log(res)
})
}
and this is radio button
<Form className='w-100' onSubmit={handleSubmit}>
<Row>
{listQuisioner.map((item) => {
return (
<Col key={item.question_id} md={6} xs={12} className='mb-3'>
<Card>
<Card.Body style={{ position: 'relative' }}>
<h4 className='text-capitalize'>{item.question}</h4>
<div className='navbar-top-line mb-4'/>
{item.question_choice.map(res => {
return (
<fieldset key={res.choice_id} id={res.choice_id}>
<label className='text-capitalize'>{res.choice}</label>
<input
type='radio'
id={res.choice_id}
value={res.choice_id}
name={res.choice}
checked={res.choice_id ? selected : null }
onChange={() => handleSelected(res.choice_id, item.question_id)}
/>
</fieldset>
)
})}
</Card.Body>
</Card>
</Col>
)
})}
<Col xs={12} className='p-3 mb-5'>
<Button variant='danger' block type='submit'>
<h5 className='mb-0'>Submit</h5>
</Button>
</Col>
</Row>
</Form>
You can use useState() hook from React to hold the quisionerId,questionChoiceId in state.
[quisionerId,setQuisionerId] = React.useState("");
[questionChoiceId,setQuestionChoiceId] =React.useState("");
//On handle selected
const handleSelected = (choiceId, questionId) => {
setQuisionerId({choice_id : choiceId, question_id : questionId);
setQuestionChoiceId(choiceId)
}

React: Table search query doesn't filter the table data

I've got a table with data that I'm getting from props. Here is the structure of the data:
[{user1: value, data1: value}, {user2: value, data2: value}]
What I'm trying to do, is to write a 'Search field' and a 'Column selector' that will filter the table inputs by the input query (this query will be checked only in the chosen column scope).
This is how the code looks like now:
class App extends React.Component {
state = {
query: '',
columnToQuery: 'user'
}
componentDidMount = () => {
const { loadTestData } = this.props;
loadTestData();
}
getTableRows = () => {
// testData format is:
// [{user1: value, data1: value}, {user2: value, data2: value}]
const { testData } = this.props;
const testDataFiltered = this.state.query
? testData.filter(elem => elem[this.state.columnToQuery].includes(this.state.query))
: testData
return testDataFiltered.map(item => ({
// Id - uuid timestamp
id: `${uuidv1()}`,
row: [
moment(item.date).format('DD.MM.YYYY HH:mm:ss'),
item.user,
}));
}
render() {
const { testData } = this.props;
console.log(this.state);
if (!testData) {
return (
<div className="loader-view mt-25 w-100">
<CircularProgress />
</div>
);
}
return (
<div className="app-wrapper">
<div id="my-tasks-page" className="row animated slideInUpTiny animation-duration-3">
<CardBox
styleName="col-12"
cardStyle="p-0"
heading={<IntlMessages id="pages.testData" />}
headerOutside
>
<Paper>
<TextField
id="dataSearch"
label="Search field"
type="search"
margin="normal"
value={this.state.query}
onChange={(event) =>
this.setState({ query: event.target.value })
}
fullWidth
/>
<FormControl className="w-100 mb-2">
<InputLabel htmlFor="">Select a column</InputLabel>
<Select
value={this.state.columnToQuery}
onChange={(event) =>
this.setState({ columnToQuery: event.target.value })
}
>
<MenuItem value='date'>Date</MenuItem>
<MenuItem value='user'>Executant</MenuItem>
</Select>
</FormControl>
<DataTable
columns={columns}
data={this.getTableRows()}
query={this.state.query}
columnToQuery={this.state.columnToQuery}
noDataMessage="Currently there are no info"
/>
</Paper>
</CardBox>
</div>
</div>
);
}
}
I consoled log the state and testData array, filter function in getTableRows() is working properly, but table is not rerendering with a filtered data, what may be a reason?

setState within componentDidUpdate comparing prev with current state not working to re-render page with new data, also getting infinite loop

I am relatively beginner in React, and in this particular situation, I am probably missing something very fundamental.
Here, I have a simple CRUD app, and after user adds new data, the updated list of items should be rendered. And the new data is added with a second Dialog component AddNewDevelopmentWork.js
So, after new data is added by the AddNewDevelopmentWork.js (which is the child compoenent that will only open a dialog for the user to input and fill few TestFields), in the main component (DevelopmentList.js), I am using componentDidUpdate to do the comparison with current state and prevState (for the state variable allDevelopmentWorks which is an array of objects) , and if they are not equal then make a request to the backend Express API and fetchin data and updating state within componentDidUpdate. And then render with new data.
Problem is, this main DevelopmentList.js component is not rendering the new data entered by the user till the page is refreshed. But after refreshing the page manually its showing the newly entered data.
Here is my DevelopmentList component.
class DevelopmentList extends Component {
constructor(props) {
super(props);
this.state = {
allDevelopmentWorks: []
};
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.allDevelopmentWorks.length !==
prevState.allDevelopmentWorks.length
) {
return axios
.get("/api/developmenties")
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
componentDidMount() {
axios.get("/api/developmenties").then(res => {
this.setState({
allDevelopmentWorks: res.data
});
});
}
render() {
const { classes } = this.props;
return (
<div>
<Table className={classes.table}>
<TableHead>
<TableRow className={classes.row}>
<CustomTableCell align="left">Location</CustomTableCell>
<CustomTableCell align="left">
Description Of Work
</CustomTableCell>
<CustomTableCell align="left">
Date of Commencement
</CustomTableCell>
<CustomTableCell align="left">Date of Completion</CustomTableCell>
<CustomTableCell align="left">Status of Work</CustomTableCell>
</TableRow>
</TableHead>
<TableBody>
{this.state.allDevelopmentWorks.map((document, i) => (
<TableRow className={classes.row} key={i}>
<CustomTableCell component="th" scope="row">
{document.location}
</CustomTableCell>
<CustomTableCell align="left">
{document.work_description}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_commencement).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_completion).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{document.status_of_work}
</CustomTableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
}
export default withStyles(styles)(DevelopmentList);
However, withing the componentDidUpdate method below, if I change it to as below the if condition (taking the length propery out of equation) then the new data is immediately rendered on the page, but then it also becomes an infinite loop inside componentDidUpdate and hitting the Express API again and again each second.
componentDidUpdate(prevProps, prevState) {
if (
this.state.allDevelopmentWorks !==
prevState.allDevelopmentWorks
) {
return axios
.get("/api/developmenties")
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
The code in the second component, (which is the child component to the main DevelopmentList.jscomponent, that will only open a dialog for the user to input and fill few TestFields add new data to this CRUD) is below AddNewDevelopmentWork.js
class AddNewDevelopmentWork extends Component {
state = {
open: false,
location: "",
work_description: "",
date_of_commencement: new Date(),
date_of_completion: new Date(),
status_of_work: "",
vertical: "top",
horizontal: "center"
};
handleCommencementDateChange = date => {
this.setState({
date_of_commencement: date
});
};
handleCompletionDateChange = date => {
this.setState({
date_of_completion: date
});
};
handleToggle = () => {
this.setState({
open: !this.state.open
});
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.props.history.push("/dashboard/developmentworks");
};
onChange = e => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState(state);
};
handleFormSubmit = e => {
e.preventDefault();
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
} = this.state;
axios
.post("/api/developmenties/", {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
})
.then(() => {
// this.props.history.push("/dashboard/developmentworks");
// window.location.href = window.location.href;
this.setState({
open: false,
vertical: "top",
horizontal: "center"
});
})
.catch(error => {
alert("Ooops something wrong happened, please try again");
});
};
handleCancel = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work,
vertical,
horizontal
} = this.state;
return (
<MuiThemeProvider theme={theme}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div>
<MuiThemeProvider theme={theme}>
<Dialog open={this.state.open} onClose={this.handleToggle}>
<DialogContent required>
<form onSubmit={this.handleFormSubmit}>
<TextField
value={location}
onChange={e =>
this.setState({
location: e.target.value
})
}
error={location === ""}
helperText={
location === "" ? "Please enter Location" : " "
}
label="Location"
type="email"
fullWidth
/>
<TextField
value={work_description}
onChange={e =>
this.setState({
work_description: e.target.value
})
}
error={work_description === ""}
helperText={
work_description === ""
? "Please enter Work Description"
: " "
}
label="Description of Work"
type="email"
fullWidth
/>
<div>
<DatePicker
format="dd/MM/yyyy"
label="Date of Commencement"
value={date_of_commencement}
onChange={this.handleCommencementDateChange}
disableOpenOnEnter
animateYearScrolling={false}
/>
</div>
<div>
<DatePicker
format="dd/MM/yyyy"
label="Date of Completion"
value={date_of_completion}
onChange={this.handleCompletionDateChange}
/>
</div>
<TextField
value={status_of_work}
onChange={e =>
this.setState({
status_of_work: e.target.value
})
}
error={location === ""}
helperText={
status_of_work === ""
? "Please enter Status of Work!"
: " "
}
label="Status of Work"
type="email"
fullWidth
/>
</form>
</DialogContent>
<DialogActions>
<Button
onClick={this.handleCancel}
classes={{
root: classes.root
}}
variant="contained"
>
Cancel
</Button>
<Button
onClick={this.handleFormSubmit}
color="primary"
variant="contained"
>
Save
</Button>
</DialogActions>
</Dialog>
</MuiThemeProvider>
</div>
</MuiPickersUtilsProvider>
</MuiThemeProvider>
);
}
}
The problem is that you are not treating your state as if it were immutable (as recommended by the React documentation). When you call this.setState({ allDevelopmentWorks: res.data }), you are replacing the value of allDevelopmentWorks with a new array with a new object reference. Because the array references do not match, checking for equality directly will fail (i.e. this.state.allDevelopmentWorks !== prevState.allDevelopmentWorks is comparing object references).
Checkout this answer for updating a state array without mutating it.
And take a look at loadash isEqual for comparing array equality.
The resulting infinite loop occurring has little to do with React itself but rather how javascript handles comparison between two objects. Since data type returned from the API is an array
[] !== [] => // true
The condition will always be true and hence setState is called repeatedly for every state change and this will trigger a re-render. A better understanding of how the different component lifecycle methods are invoked is one of the core concepts that I had to get a hang of when in my early days of learning React.
componentWillMount ->
render ->
componentDidMount(state changes here will trigger a re-render from maybe an api fetch) ->
componentWillUpdate ->
render ->
componentDidUpdate
You could share a link to the repo if it there is one and I can have a look
If you use setState inside componentDidUpdate it updates the component, resulting in a call to componentDidUpdate which subsequently calls setState again resulting in the infinite loop. You should conditionally call setState and ensure that the condition violating the call occurs eventually e.g:
componentDidUpdate: function() {
if (condition) {
this.setState({..})
} else {
//do something else
}
}
In case you are only updating the component by sending props to it(it is not being updated by setState, except for the case inside componentDidUpdate), you can call setState inside componentWillReceiveProps instead of componentDidUpdate.
Answering my own question, after I resolved the issue. It was a problem of not updating the parent component's (DevelopmentList.js) state at all when the user was adding a new item with the child component.(AddNewDevelopmentWork.js which is a form Dialog).
So, it was case of passing data from child to parent to update parent's state as below
A> Define a callback in my parent (addItem function) which takes
the data I need in as a parameter.
B> Pass that callback as a prop to the child
C> Call the callback using this.props.[callback] inside the child,
and pass in the data as the argument.
Here's my final working code in the parent DevelopmentList.js
class DevelopmentList extends Component {
constructor(props) {
super(props);
this.state = {
allDevelopmentWorks: []
};
}
addItem = item => {
this.setState({
allDevelopmentWorks: [item, ...this.state.allDevelopmentWorks]
});
};
componentDidMount() {
axios.get("/api/developmenties").then(res => {
this.setState({
allDevelopmentWorks: res.data
});
});
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.allDevelopmentWorks.length !==
prevState.allDevelopmentWorks.length
) {
return axios
.get("/api/developmenties")
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
deleteDevelopmentWorks = id => {
axios.delete("/api/developmenties/" + id).then(() => {
this.setState({
allDevelopmentWorks: this.state.allDevelopmentWorks.filter(
item => item._id !== id
)
});
});
};
render() {
const { classes } = this.props;
return (
<div>
<AddNewDevelopmentWork addNewItemToParentState={this.addItem} />
<Table className={classes.table}>
<TableBody>
{this.state.allDevelopmentWorks.map((document, i) => (
<TableRow className={classes.row} key={i}>
<CustomTableCell component="th" scope="row">
{document.location}
</CustomTableCell>
<CustomTableCell align="left">
{document.work_description}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_commencement).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{moment(document.date_of_completion).format("YYYY-MM-DD")}
</CustomTableCell>
<CustomTableCell align="left">
{document.status_of_work}
</CustomTableCell>
<CustomTableCell align="left">
<div id="snackbar">
The Document has been successfully deleted
</div>
<Button
onClick={this.deleteDevelopmentWorks.bind(
this,
document._id
)}
variant="contained"
className={classes.button}
>
<DeleteIcon className={classes.rightIcon} />
</Button>
</CustomTableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
}
export default withStyles(styles)(DevelopmentList);
And here's my final working code in the child AddNewDevelopmentWork.js
class AddNewDevelopmentWork extends Component {
state = {
open: false,
opensnackbar: false,
vertical: "top",
horizontal: "center",
location: "",
work_description: "",
date_of_commencement: new Date(),
date_of_completion: new Date(),
status_of_work: ""
};
handleCommencementDateChange = date => {
this.setState({
date_of_commencement: date
});
};
handleCompletionDateChange = date => {
this.setState({
date_of_completion: date
});
};
handleToggle = () => {
this.setState({
open: !this.state.open
});
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ opensnackbar: false });
this.props.history.push("/dashboard/developmentworks");
};
onChange = e => {
const state = this.state;
state[e.target.name] = e.target.value;
this.setState(state);
};
handleFormSubmit = e => {
e.preventDefault();
const { addNewItemToParentState } = this.props;
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
} = this.state;
axios
.post("/api/developmenties/", {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
})
.then(() => {
addNewItemToParentState({
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work
});
this.setState({
open: false,
opensnackbar: true,
vertical: "top",
horizontal: "center"
});
})
.catch(error => {
alert("Ooops something wrong happened, please try again");
});
};
handleCancel = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
const {
location,
work_description,
date_of_commencement,
date_of_completion,
status_of_work,
vertical,
horizontal,
opensnackbar
} = this.state;
return (
<MuiThemeProvider theme={theme}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div>
<MuiThemeProvider theme={theme}>
<Fab
variant="fab"
onClick={this.handleClickOpen}
aria-pressed="true"
color="secondary"
size="large"
aria-label="Add"
fontSize="large"
>
<AddIcon className={styles.largeIcon} />
</Fab>
<Dialog
open={this.state.open}
onClose={this.handleToggle}
aria-labelledby="form-dialog-title"
fullWidth={true}
maxWidth={"md"}
>
<DialogTitle
id="form-dialog-title"
disableTypography="false"
className={this.props.classes.styledHeader}
>
New Development Work
</DialogTitle>
<DialogContent required>
<form onSubmit={this.handleFormSubmit}>
<TextField
value={location}
onChange={e =>
this.setState({
location: e.target.value
})
}
type="email"
/>
<TextField
value={work_description}
onChange={e =>
this.setState({
work_description: e.target.value
})
}
type="email"
/>
<div>
<DatePicker
value={date_of_commencement}
onChange={this.handleCommencementDateChange}
/>
</div>
<div>
<DatePicker
value={date_of_completion}
onChange={this.handleCompletionDateChange}
/>
</div>
<TextField
value={status_of_work}
onChange={e =>
this.setState({
status_of_work: e.target.value
})
}
type="email"
fullWidth
/>
</form>
</DialogContent>
<DialogActions>
<Button
onClick={this.handleCancel}
classes={{
root: classes.root
}}
variant="contained"
>
Cancel
</Button>
<Button
onClick={this.handleFormSubmit}
color="primary"
variant="contained"
>
Save
</Button>
</DialogActions>
</Dialog>
<Snackbar
anchorOrigin={{ vertical, horizontal }}
open={opensnackbar}
autoHideDuration={2000}
onClose={this.handleClose}
>
<MySnackbarContent
onClose={this.handleClose}
variant="success"
message="New Development Works has been uploaded successfully"
/>
</Snackbar>
</MuiThemeProvider>
</div>
</MuiPickersUtilsProvider>
</MuiThemeProvider>
);
}
}
AddNewDevelopmentWork.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(AddNewDevelopmentWork);

Categories

Resources