nkocev
nkocev

Reputation: 15

React, setting initial value to input element

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.

Upvotes: 1

Views: 25680

Answers (2)

hbentlov
hbentlov

Reputation: 544

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>
    );
  }
}

Upvotes: 4

Root
Root

Reputation: 2361

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}/>

Upvotes: 2

Related Questions