Search code examples
reactjsreact-component

how to render the updated values from the input fields in the child component


I have a react js parent component.When it is being called a Welcome page opens up which shows the records of the users.There is also a sign up button on this page.When the sign up button is clicked a dialog box is opened which asks for user details.My requirement is that data should flow from the dialog box to the welcome page(along with users which were earlier rendered).It should include updated record.I have tried to use callback function.

My Todo component:

import React, { Component } from 'react';
import './Todo.css';
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,
    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(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 });
  }

  signUpDialog() {
    this.setState({ view: true });
  }

  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(p1, p2, p3, p4) {
    this.setState({ students: [...this.state.students, { id: { p1 }, name: { p2 }, age: { p3 }, email: { p4 } }] });
  }

  render() {
    return (
      <div style={{ width: '500px', background: 'beige' }}>
        <form>
          <button onClick={this.signUpDialog.bind(this)}>Sign-UP</button>
          {this.state.view ? <FormDialog details={this.onSubmitHandle} /> : 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.onEditHandle.bind(this, abc.id, abc.name, abc.age, abc.email)}>Edit</button>
              </tr>
            ))}
          </table>
        </form>{' '}
      </div>
    );
  }
}

export default Todo;

The following is my child component which has a dialog box.

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 FormDialog extends Component {
  constructor(props) {
    super(props);
    this.state = { edit: false, view: true };
    this.onSubmitForm = this.onSubmitForm.bind(this);
  }
  handleClose() {
    this.setState({ view: !this.state.view });
  }
  onDeleteHandle() {
    let id = arguments[0];
    this.setState({
      students: this.state.students.filter(item => {
        if (item.id !== id) {
          return item;
        }
      })
    });
  }

  onEditHandle(event) {
    this.setState({ edit: true, id: arguments[0], name: arguments[1], age: arguments[2], email: arguments[3] });
  }
  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.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>
      );
    }
  }

  onSubmitForm(event) {
    this.props.details(
      event.target.id.value,
      event.target.item.value,
      event.target.xyz.value,
      event.target.email.value
    );
  }

  render() {
    return (
      <div>
        <Dialog fullWidth open={this.state.view} onClose={this.handleClose.bind(this)}>
          <DialogTitle>Sign Up Provide Details</DialogTitle>
          <DialogContent>
            {this.renderEditForm()}

            <DialogContentText>
              <div>
                <form onSubmit={e => this.onSubmitForm(e)}>
                  <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>
              </div>
            </DialogContentText>
          </DialogContent>
          <DialogActions>
            <Button onClick={this.handleClose.bind(this)} color="primary">
              Cancel
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

export default FormDialog;

As you can see the form upon submission calls a onSubmitForm() which in turns passes the values of the 4 input fields to the parent component.The values are reaching the parent component as i check with alert(p1),alert(p2),alert(p3) and alert(p4). But i am not able to set the state of the student array as defined by using this.setState({students: [...this.state.students, {id:{p1},name:{p2},age:{p3},email:{p4}}] }).

Any help as how i can set the state of the students array and re-render the entire array in the page.


Solution

  • There are multiple issues here:

    This is first one.

    {
      id: { p1: 123 },
      name: { p2: 'test name' },
      age: { p3: 18 },
      email: { p4: '[email protected] }
    }
    

    But you need to generate like

    {
      id: 123,
      name: 'test name',
      age: 18,
      email: '[email protected]
    }
    

    So make this change in your function.

    onSubmitHandle(p1,p2,p3,p4) { 
      this.setState({students: [...this.state.students, {
        id:p1,
        name:p2,
        age:p3,
        email:p4
      }]})
    };
    

    Even better would name your argument the same as the key.

    onSubmitHandle(id,name,age,email) { 
      this.setState({students: [...this.state.students, {
        id,
        name,
        age,
        email
      }]})
    }; 
    

    Bind your handler while passing to dialog.

    <FormDialog details={this.onSubmitHandle.bind(this)} />
    

    And you need to use event.preventDefault in your form submit action.

    onSubmitForm(event) {
        event.preventDefault();
        this.props.details(
          event.target.id.value,
          event.target.item.value,
          event.target.xyz.value,
          event.target.email.value
        );
      }
    

    I have created sandbox and fixed your issues:

    Edit fragrant-sun-ehflg