Reputation: 119
I have a root component.From that I am calling the welcome page which is displaying the details of the students already registered along with edit and delete button in each row. The delete function is working fine which is used to delete a row,But my requirement is that when i click on the edit button,the details of the student selected, should auto populate in the dialog box and once updating is complete,the finalized result should be published back to the starting page. App-->Todo.js-->EditDialog.js
App.js
import React, { Component } from 'react';
import FormDialog from './FormDialog'
import Todo from './ToDo'
import EditDialog from './EditDialog'
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
mode: false
};
}
showForm()
{
this.setState({mode:!this.state.mode})
}
render() {
return (
<div className="App">
<button onClick={this.showForm.bind(this)}>Welcome</button>
{this.state.mode? <Todo/>:null}
</div>
);
}
}
export default App;
Todo.js
import React, { Component } from 'react';
import './Todo.css'
import EditDialog from './EditDialog'
import FormDialog from './FormDialog'
import Dialog from '@material-ui/core/Dialog';
import { thisExpression } from '@babel/types';
class Todo extends Component {
state = { edit: false, id: null,view:false,editview:false,
students: [
{ id: 1, name: 'Wasif', age: 21, email: '[email protected]' },
{ id: 2, name: 'Ali', age: 19, email: '[email protected]' },
{ id: 3, name: 'Saad', age: 16, email: '[email protected]' },
{ id: 4, name: 'Asad', age: 25, email: '[email protected]' },
{ id: 5, name: 'kiwi', age: 20, email: '[email protected]' }
], }
onDeleteHandle() {let id = arguments[0];
this.setState({students:this.state.students.filter(item => {if (item.id !== id)
{return item;}})});}
onUpdateHandle(id,name,age,email){
this.setState({students: this.state.students.map(item => {
if (item.id === this.state.id){
item['id'] = id;
item['name']=name;
item['age']=age;
item['email']=email;
}return item;})})
this.setState({edit: false});
}
signUpDialog(){
this.setState({view:!this.state.view})
}
editFormDialog(){
this.setState({editview:!this.state.editview})
}
renderEditForm() {
if (this.state.edit) {
return <form onSubmit={this.onUpdateHandle.bind(this)}>
<input type="text" name="updatedItem" className="item" defaultValue={this.state.id} />
<input type="text" name="updatedItem1" className="item" defaultValue={this.state.name} />
<input type="text" name="updatedItem2" className="item" defaultValue={this.state.age} />
<input type="text" name="updatedItem3" className="item" defaultValue={this.state.email} />
<button className="update-add-item">Update</button>
</form> } }
onEditHandle(event) {
this.setState({edit: true,id: arguments[0],name:arguments[1],age:arguments[2],email:arguments[3]});}
onSubmitHandle(id,name,age,email) {
this.setState({students: [...this.state.students, {
id:id,
name:name,
age:age,
email:email
}]})
};
render()
{
return<div style={{width: "500px",background : "beige"}} >
<button onClick={this.signUpDialog.bind(this)}>Sign-UP</button>
{this.state.view? <FormDialog details={this.onSubmitHandle.bind(this)}/> :null}
<table>{this.state.students.map(abc => (<tr><td>{abc.id}</td><td>{abc.name}</td><td>{abc.age}</td><td>{abc.email}</td><td>
<button onClick={this.onDeleteHandle.bind(this, abc.id)}>Delete</button></td>
<button onClick={this.editFormDialog.bind(this)}>Edit</button>
{this.state.editview? <EditDialog updDetails={this.onUpdateHandle.bind(this)}/>:null}
</tr>))}</table> </div>
}
}
export default Todo;
EditDialog.js
import React, {Component} from 'react';
import Todo from './ToDo'
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
class EditDialog extends Component{
constructor(props){
super(props);
this.state={editDetails: true,view:false}
}
onUpdateHandle(event){
event.preventDefault();
this.setState({students: this.state.students.map(item => {
if (item.id === this.state.id){
item['id'] = event.target.updatedItem.value;
item['name']=event.target.updatedItem1.value;
item['age']=event.target.updatedItem2.value;
item['email']=event.target.updatedItem3.value;
}return item;})})
this.setState({edit: false});
}
renderEditForm() {
if (this.state.editDetails) {
return <form onSubmit={this.onUpdateHandle.bind(this)}>
<input type="text" name="updatedItem" className="item" defaultValue={this.state.id} />
<input type="text" name="updatedItem1" className="item" defaultValue={this.state.name} />
<input type="text" name="updatedItem2" className="item" defaultValue={this.state.age} />
<input type="text" name="updatedItem3" className="item" defaultValue={this.state.email} />
<button className="update-add-item">Update</button>
</form> } }
handleClose(){
this.setState({view:!this.state.view})
}
render()
{
return(
<div>
<Dialog open>
<DialogTitle>Edit The Details</DialogTitle>
<form>
<label >ID</label>
<input type="number" name="id" className="item" />
<label>Name</label>
<input type="text" name="item" className="item" />
<label>age</label>
<input type="number" name="xyz" className="item" />
<label>email</label>
<input type="text" name="email" className="item" />
<button className="btn-add-item" >Add</button>
</form>
<Button onClick={this.handleClose.bind(this)} color="primary">
Cancel
</Button></Dialog>
</div> )
}
}
export default EditDialog;
I have used Callback function and passing the updating function. But for the EditDialog box,the details arent autopopulating and also i need to perform the update in dialog box and publish the result back.
Upvotes: 1
Views: 2715
Reputation: 3442
A Problem:
You put your <EditDialog />
into your Array loop (students.map
) in the file ToDo.js
, so when your state (state.editview
) becomes true
you have 5 dialogs that are shown together, so you cannot see the first one.
So lets put it outside of your loop (map):
// FROM HERE
</tr>))
}
</table>
// TO HERE
{this.state.editview? <EditDialog updDetails={this.onUpdateHandle.bind(this)}/>:null}
</div>
Your Answer:
You should pass the current student as a props to your dialog, so you can view the one that is clicked. Something similar to your onDeleteHandle
function. Do the steps below:
1) Add a state of your currentStudent
to your ToDo
state:
state = {
edit: false, id: null, view: false, editview: false,
students: [
{id: 1, name: 'Wasif', age: 21, email: '[email protected]'},
{id: 2, name: 'Ali', age: 19, email: '[email protected]'},
{id: 3, name: 'Saad', age: 16, email: '[email protected]'},
{id: 4, name: 'Asad', age: 25, email: '[email protected]'},
{id: 5, name: 'kiwi', age: 20, email: '[email protected]'}
],
currentStudent: {} // ADD THIS ONE
}
2) Pass your student ID to your function editFormDialog
just like your delete one: (abc.id)
<button onClick={this.editFormDialog.bind(this, abc.id)}>Edit</button>
3) In your editFormDialog
function find your student just like the one you did in onUpdateHandle
but this time you have to find the equal ID and update your currentStudent
state:
editFormDialog() {
let id = arguments[0]; // Or better to pass it as a parameter: editFormDialog(id) { ... }
this.setState({
currentStudent: this.state.students.filter(item => {
if (item.id === id) { // IDs should be Equal
return item;
}
})
});
this.setState({editview: !this.state.editview})
}
4) Now you have your currentStudent
in your state. So you have to have it in your <EditDialog />
, and so you can access it into your EditDialog
class (EditDialog.js). Add a property to your <EditDialog />
, I named it currentStudent
like this:
{
this.state.editview
? <EditDialog
currentStudent={this.state.currentStudent} // THIS PROPERTY
updDetails={this.onUpdateHandle.bind(this)}
/>
: null
}
5) Now you can access your currentStudent in the EditDialog
class like this:
// Add a State to EditDialog
this.state = {
editDetails: true,
view: false,
updatedValues: {
id: null,
email: null
}
}
// We use this to Mount it for the first time (Prevent Loop Renders)
componentDidMount() {
this.setState({
updatedValues: {
id: this.props.currentStudent[0].id,
email: this.props.currentStudent[0].email
}
});
}
// We should do this to update the input value to the state
<input type="text" name="email" className="item" onInput={this.updateStateHandler} value={this.state.updatedValues.email}/>
// And we of course need the updateHandler method
updateStateHandler = (e) => {
this.setState({
updatedValues: {
...this.state.updatedValues,
email: e.target.value
}
});
};
I've just filled the email input in the render()
method. You could fill the other ones too.
6) Now for passing the data back to the your ToDo and update the table with the new values, you have to add handleUpdate
method in your dialog like this:
handleUpdate(e) {
e.preventDefault();
this.props.closeModal();
this.props.updateStudentHandler(this.state.updatedValues);
}
7) So you need to pass closeModal
and updateStudentHandler
from your ToDo class. Your EditDialog should be something like this:
<EditDialog
currentStudent={this.state.currentStudent}
updDetails={this.onUpdateHandle.bind(this)}
updateStudentHandler={this.updateStudent}
closeModal={this.closeModal}
/>
And the handlers:
updateStudent = (updatedValues) => {
let newStudents = [...this.state.students];
newStudents.map(
student => {
if (student.id === updatedValues.id) {
student.email = updatedValues.email;
}
}
);
this.setState({
students: newStudents
});
}
closeModal = () => {
this.setState({
editview: false
});
}
NOTE 1: To closing the dialog, I saw that you change the state of the EditDialog class which was wrong. You should handle that in your ToDo state like the closeModal method at the top.
NOTE 2: To access this
in the methods above, you should use ES6 arrow functions.
At last your ToDo
and EditDialog
classes should look like this:
ToDo.js
import React, {Component} from 'react';
import './Todo.css'
import EditDialog from './EditDialog'
import FormDialog from './FormDialog'
import Dialog from '@material-ui/core/Dialog';
import {thisExpression} from '@babel/types';
class Todo extends Component {
state = {
edit: false, id: null, view: false, editview: false,
students: [
{id: 1, name: 'Wasif', age: 21, email: '[email protected]'},
{id: 2, name: 'Ali', age: 19, email: '[email protected]'},
{id: 3, name: 'Saad', age: 16, email: '[email protected]'},
{id: 4, name: 'Asad', age: 25, email: '[email protected]'},
{id: 5, name: 'kiwi', age: 20, email: '[email protected]'}
],
currentStudent: {}
}
onDeleteHandle() {
let id = arguments[0];
this.setState({
students: this.state.students.filter(item => {
if (item.id !== id) {
return item;
}
})
});
}
onUpdateHandle(id, name, age, email) {
this.setState({
students: this.state.students.map(item => {
if (item.id === this.state.id) {
item['id'] = id;
item['name'] = name;
item['age'] = age;
item['email'] = email;
}
return item;
})
})
this.setState({edit: false});
}
signUpDialog() {
this.setState({view: !this.state.view})
}
editFormDialog(id) {
// let id = arguments[0];
this.setState({
currentStudent: this.state.students.filter(item => {
if (item.id === id) {
return item;
}
})
});
this.setState({editview: !this.state.editview})
}
updateStudent = (updatedValues) => {
let newStudents = [...this.state.students];
newStudents.map(
student => {
if (student.id === updatedValues.id) {
student.name = updatedValues.name;
student.age = updatedValues.age;
student.email = updatedValues.email;
}
}
);
this.setState({
students: newStudents
});
}
closeModal = () => {
this.setState({
editview: false
});
}
renderEditForm() {
if (this.state.edit) {
return <form onSubmit={this.onUpdateHandle.bind(this)}>
<input type="text" name="updatedItem" className="item" defaultValue={this.state.id}/>
<input type="text" name="updatedItem1" className="item" defaultValue={this.state.name}/>
<input type="text" name="updatedItem2" className="item" defaultValue={this.state.age}/>
<input type="text" name="updatedItem3" className="item" defaultValue={this.state.email}/>
<button className="update-add-item">Update</button>
</form>
}
}
onEditHandle(event) {
this.setState({edit: true, id: arguments[0], name: arguments[1], age: arguments[2], email: arguments[3]});
}
onSubmitHandle(id, name, age, email) {
this.setState({
students: [...this.state.students, {
id: id,
name: name,
age: age,
email: email
}]
})
};
render() {
return <div style={{width: "500px", background: "beige"}}>
<table>
<tbody>
{
this.state.students.map(abc => (<tr key={abc.id}>
<td>{abc.id}</td>
<td>{abc.name}</td>
<td>{abc.age}</td>
<td>{abc.email}</td>
<td>
<button onClick={this.onDeleteHandle.bind(this, abc.id)}>Delete</button>
</td>
<td>
<button onClick={this.editFormDialog.bind(this, abc.id)}>Edit</button>
</td>
</tr>))
}
</tbody>
</table>
{
this.state.editview
? <EditDialog
currentStudent={this.state.currentStudent}
updDetails={this.onUpdateHandle.bind(this)}
updateStudentHandler={this.updateStudent}
closeModal={this.closeModal}
/>
: null
}
</div>
}
}
export default Todo;
EditDialog.js
import React, {Component} from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
class EditDialog extends Component {
constructor(props) {
super(props);
this.state = {
editDetails: true,
view: false,
updatedValues: {
id: null,
name: null,
age: null,
email: null
}
}
}
onUpdateHandle(event) {
event.preventDefault();
this.setState({
students: this.state.students.map(item => {
if (item.id === this.state.id) {
item['id'] = event.target.updatedItem.value;
item['name'] = event.target.updatedItem1.value;
item['age'] = event.target.updatedItem2.value;
item['email'] = event.target.updatedItem3.value;
}
return item;
})
})
this.setState({edit: false});
}
renderEditForm() {
if (this.state.editDetails) {
return <form onSubmit={this.onUpdateHandle.bind(this)}>
<input type="text" name="updatedItem" className="item" defaultValue={this.state.id}/>
<input type="text" name="updatedItem1" className="item" defaultValue={this.state.name}/>
<input type="text" name="updatedItem2" className="item" defaultValue={this.state.age}/>
<input type="text" name="updatedItem3" className="item" defaultValue={this.state.email}/>
<button className="update-add-item">Update</button>
</form>
}
}
handleClose() {
this.setState({view: !this.state.view})
}
handleUpdate(e) {
e.preventDefault();
this.props.closeModal();
this.props.updateStudentHandler(this.state.updatedValues);
}
updateStateHandler = (e) => {
let newUpdatedValues = {};
switch (e.target.name) {
case 'name':
newUpdatedValues = {
...this.state.updatedValues,
name: e.target.value
};
break;
case 'age':
newUpdatedValues = {
...this.state.updatedValues,
age: e.target.value
};
break;
case 'email':
newUpdatedValues = {
...this.state.updatedValues,
email: e.target.value
};
break;
default:
break;
}
this.setState({
updatedValues: newUpdatedValues
});
};
componentDidMount() {
this.setState({
updatedValues: {
id: this.props.currentStudent[0].id,
name: this.props.currentStudent[0].name,
age: this.props.currentStudent[0].age,
email: this.props.currentStudent[0].email
}
});
}
render() {
return (
<div>
<Dialog open>
<DialogTitle>Edit The Details</DialogTitle>
<form>
<label>ID</label>
<input type="number" name="id" className="item"
value={this.state.updatedValues.id} />
<label>Name</label>
<input type="text" name="name" className="item"
onInput={this.updateStateHandler}
value={this.state.updatedValues.name} />
<label>age</label>
<input type="number" name="age" className="item"
onInput={this.updateStateHandler}
value={this.state.updatedValues.age} />
<label>email</label>
<input type="text" name="email" className="item"
onInput={this.updateStateHandler}
value={this.state.updatedValues.email} />
<button className="btn-add-item" onClick={this.handleUpdate.bind(this)}>Add</button>
</form>
<Button onClick={this.handleClose.bind(this)} color="primary">
Cancel
</Button></Dialog>
</div>)
}
}
export default EditDialog;
Upvotes: 1