2

I have a list of students on my page. When I click on some student, a form should appear with input element for all of student's properties. When form is submitted, student's properties should change. The problem is when I want to set initial value of input elements as a properties of a current selected student. The value of input elements is filled with properties of a current student, but when I try to type something in that input, it's value does not change. Code of Parent component

class App extends Component {
      constructor(props){
        super(props);
        this.state = {
          students :listStudents(),
            visible: false,
            index: 0,
            student: listStudents()[0]
        };
        this.onClick = this.onClick.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
        this.onNewStudentSubmit = this.onNewStudentSubmit.bind(this);
      }

      onClick(index){
        if(this.state.visible){
          this.setState({
              visible: false,
              index: 0
          });
        }
        else {
            let student1 = this.state.students
                .filter(s => s.index === index);
          this.setState({
              visible: true,
              index: index,
              student: student1[0]
          });
        }
      }

      onSubmit(student){
          let list = this.state.students
              .map(s => {
                if(s.index === this.state.index)
                  return student;
                return s;
              });
        this.setState({
           students : list,
           visible: false
        });
      }

      render() {
        return (
          <div className="App">
            <StudentsList students={this.state.students} onClick={this.onClick}/>
            <EditStudentDetails student={this.state.student} visible={this.state.visible} onSubmit={this.onSubmit}/>
              <CreateStudent onSubmit={this.onNewStudentSubmit}/>
          </div>
        );
      }
    }

    export default App;

onClick function changes selected student and stores it in state.student. onSubmit function is triggered when the student's editing form is submitted. Render returns the list of all students and a editing component which can be visible or not. Below is code of my editing component.

import React from 'react';

class EditStudentDetails extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            name: "",
            surname: "",
            index : "",
            class : "",
            visible: ""
        };
        this.handleSubmit = this.handleSubmit.bind(this);
        this.handleNameChange = this.handleNameChange.bind(this);
        this.handleSurnameChange = this.handleSurnameChange.bind(this);
        this.handleClassChange = this.handleClassChange.bind(this);
        this.handleIndexChange = this.handleIndexChange.bind(this);
    }


    handleSubmit(e){
        const student = {
            name: this.state.name,
            surname: this.state.surname,
            index : this.state.index,
            class : this.state.class
        };
        this.props.onSubmit(student);
        e.preventDefault();
    }

    handleNameChange(e){
        const newName = e.target.value;
        this.setState({
           name: newName
        });
    }

    handleSurnameChange(e){
        const newName = e.target.value;
        this.setState({
            surname: newName
        });
    }

    handleIndexChange(e){
        const newIndex = e.target.value;
        this.setState({
            index: newIndex
        });
    }

    handleClassChange(e){
        const newClass = e.target.value;
        this.setState({
            class: newClass
        });
    }

    render(){
        const type = this.props.visible ? {display: 'block'} : {display: 'none'} ;
        return(
            <div style={type}>
                <form className="form-group" onSubmit={this.handleSubmit}>
                    Име
                    <input className="Name" type="text" onChange={this.handleNameChange} value={this.props.student.name}/>
                    Презиме
                    <input className="Surname" type="text" onChange={this.handleSurnameChange} value={this.props.student.surname}/>
                    Индекс
                    <input className="Index" type="text" onChange={this.handleIndexChange} value={this.props.student.index}/>
                    Насока
                    <input className="Class" type="text" onChange={this.handleClassChange} value={this.props.student.class}/>
                    <input className="submit btn" type="submit" value="Промени"/>
                </form>
            </div>
        );
    }
}

export default EditStudentDetails;

I try to set initial value by setting each input's value to the appropriate prop. Then when something is changed in the input component state should update. But as I said, the value of each input does not change.

1
  • I am glad the bottom answer worked for you. Something you should be aware about though, when you use e.target.value directly in the callback, it does not run right away. Its a better practice to pull it out first as you initially had it. You could also do e.persist();. Commented Nov 6, 2018 at 21:18

2 Answers 2

4

You are telling React to use the passed prop as the input value, and since the props are not changed, the value isn't either. Set the passed props to the component state and update the state when the input is changed.

If you want to shave of some bytes, you could also use a more general onChange method as in the example below, given you are able to set a name property on the input fields.

class EditStudentDetails extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "",
      surname: "",
      index: "",
      class: "",
      visible: "",
      ...this.props.student
    };
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleSubmit(e) {
    const student = {
      name: this.state.name,
      surname: this.state.surname,
      index: this.state.index,
      class: this.state.class
    };
    this.props.onSubmit(student);
    e.preventDefault();
  }

  handleChange(e) {
    this.setState({
      [e.target.name]: e.target.value
    });
  }

  render() {
    const type = this.props.visible ? { display: 'block' } : { display: 'none' };
    return (
      <div style={type}>
        <form className="form-group" onSubmit={this.handleSubmit}>
          Име
                    <input className="Name" name="name" type="text" onChange={this.handleChange} value={this.state.name} />
          Презиме
                    <input className="Surname" name="surname" type="text" onChange={this.handleChange} value={this.state.surname} />
          Индекс
                    <input className="Index" name="index" type="text" onChange={this.handleChange} value={this.state.index} />
          Насока
                    <input className="Class" name="class" type="text" onChange={this.handleChange} value={this.state.class} />
          <input className="submit btn" type="submit" value="Промени" />
        </form>
      </div>
    );
  }
}
Sign up to request clarification or add additional context in comments.

Comments

2

The problem is here.

<input className="Name" type="text" onChange={this.handleNameChange} value={this.props.student.name}/>

The value of the input is this.props.student.name,but in the this.handleNameChange, you change this.state.name,so when you type something,you can't see the change in the input value. I suppose you need something like this:

this.state = {
   class: props.student.name
}
...
<input className="Name" type="text" onChange={this.handleNameChange} value={this.state.name}/>

1 Comment

I had already done that, but EditStudent component's state did not update when I selected different student, while the props send to EditStudent was changed. I combined your answer with updating EditComponent state on every componentWillReceiveProps method to update state every time different props was received. Thanks for the solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.