Volodymyr Humeniuk
Volodymyr Humeniuk

Reputation: 3791

Save textarea value to div with ReactJs

I'm only trying to deal with the React, so my question may seem very simple, but still I'm stuck on it.

I have two blocks (div.user-data__row) in which there are some values. I change the state of the component (handleChange function), the state in which these blocks are replaced by text fields (textarea.text), and I want when I click on the save button and call saveChange function, the value from each text field is taken and passed to the blocks (1st textarea to 1st block, etc).

I found examples of solving a similar case using the ref attribute, but later read that this is no longer an actual solution and so no one does. Please help me find the actual implementation path.

class UserData extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      edit: true,
    };

    this.handleChange = this.handleChange.bind(this);
    this.saveChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.setState(() => ({
      edit: !this.state.edit,
    }));
  }

  saveChange() {
    this.setState(() => ({
      edit: false
    }))
  }

  render() {
    if (this.state.edit) {
      return (
        <div className="user-data">
          <div className="user-data__row">{this.props.userData.name}</div>
          <div className="user-data__row">{this.props.userData.email}</div>
          <button onClick={ this.handleChange }>Edit</button>
        </div>
      );
    } else {
      return (
        <div className="user-data">
          <textarea className="text" defaultValue={this.props.userData.name}></textarea>
          <textarea className="text" defaultValue={this.props.userData.email}></textarea>
          <button onClick={ this.saveChange }>Save</button>
        </div>
      )
    }
  }
}

Upvotes: 0

Views: 4947

Answers (3)

ruanmer
ruanmer

Reputation: 31

You can also use contentEditable, which it will allow you to edit the content of the div.

class UserData extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      edit: true
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange() {
    this.setState(() => ({
      edit: !this.state.edit
    }));
  }

  render() {
    const { edit } = this.state;

    return (
      <div className="user-data">
        <div className="user-data__row" contentEditable={edit}>{this.props.userData.name}</div>
        <div className="user-data__row" contentEditable={edit}>{this.props.userData.email}</div>
        <button onClick={this.handleChange}>
          {edit ? Save : Edit}
        </button>
      </div>
    )
  }
}

Upvotes: 0

Abdennour TOUMI
Abdennour TOUMI

Reputation: 93163

Because props are read-only & because userData (email+name) can be changed inside the component , you have to populate props values in the state, then manage the state after that will be enough.

Also , you will need to convert your textarea from uncontrolled component to controlled component by:

  • Using value instead of defaultValue

  • Implementing onChange with setState of that value as handler .

  • Value of textarea should be read from state not props.

If props of <UserData /> may be updated from outside throughout its lifecycle , you will need componentWillReceiveProps later on.

Also you have a typo if (!this.state.edit) { and not if (this.state.edit) { .

class UserData extends React.Component {
    state = {
      edit: true,
      userDataName: this.props.userData.name, // Populate props values
      userDataEmail: this.props.userData.email, // Populate props values
    };
  
  
  handleChange = () => {
    this.setState((state) => ({
      edit: !state.edit,
    }));
  }

  saveChange =() => {
    this.setState(() => ({
      edit: false
    }))
  }

  render() {
    if (!this.state.edit) {
      return (
        <div className="user-data">
          <div className="user-data__row">{this.state.userDataName}</div>
          <div className="user-data__row">{this.state.userDataEmail}</div>
          <button onClick={ this.handleChange }>Edit</button>
        </div>
      );
    } else {
      return (
        <div className="user-data">
          <textarea className="text" value={this.state.userDataName}  onChange={(e) => this.setState({userDataName: e.target.value})}></textarea>
          <textarea className="text" value={this.state.userDataEmail} onChange={(e) => this.setState({userDataEmail: e.target.value})}></textarea>
          <button onClick={ this.saveChange }>Save</button>
        </div>
      )
    }
  }
}



ReactDOM.render(<UserData userData={{name: 'Abdennoor', email: '[email protected]'}} /> , document.querySelector('.app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div class="app" />

Upvotes: 3

Flying
Flying

Reputation: 4560

You're receiving values for <div> from this.props, it means that these values should came from some external source and passed to your component. A way of passing these values to component's props is out of scope of this question, it can be implemented in a very different ways. Usually it came either from parent component or from some connected store.

You need to obtain values from your <textarea> form fields, it can be done directly (using ref) or by using some third-party library that provides form handling. Then these values needs to be stored (and obtained) either directly from component's state or from external source (via props).

Unfortunately scope of your question is too broad to be able to give more precise answer, but hope that this information will lead you to some kind of solution.

Upvotes: 1

Related Questions