72

I am working on a project which is basically notepad. I am having problems though updating the <textarea>'s value when an ajax call is made. I tried setting the textarea's value property but then no changes to its value can be made. How can I make it so on a state change the textarea's value changes and can be edited.

The code I have is as follows.

In the parent class

<Editor name={this.state.fileData} />

In the Editor class

var Editor = React.createClass({
render: function() {
return (
    <form id="noter-save-form" method="POST">
    <textarea id="noter-text-area" name="textarea" value={this.props.name}></textarea>
    <input type="submit" value="Save" />
    </form>
);
}

});

I can't use defaultValue because the value of the textarea is not known on page load and when I try and put the data between the textareas nothing happens. I would like it to take the state value whenever the state changes but have it editable in between.

Thanks

Edit

I managed to get it working using jQuery but would like to do it in React instead, I called this before render:

$('#noter-text-area').val(this.props.name);
4
  • Are you looking for onChange, from the React docs? facebook.github.io/react/docs/forms.html#controlled-components Commented Oct 20, 2015 at 19:22
  • On change is for when the value of the textarea changes. I don't really need that just want the textarea to be updated upon a state change of its parent class. Commented Oct 20, 2015 at 19:27
  • Are you sure the state of the parent is actually changing? Commented Oct 20, 2015 at 19:28
  • I used a alert(this.state.fileData) to test and it seems to be. I also tried <textarea>{this.props.name}</textarea> but that doesn't work. If I change the value property it changes but then is uneditable. Commented Oct 20, 2015 at 19:31

4 Answers 4

94

I think you want something along the line of:

Parent:

<Editor name={this.state.fileData} />

Editor:

var Editor = React.createClass({
  displayName: 'Editor',
  propTypes: {
    name: React.PropTypes.string.isRequired
  },
  getInitialState: function() { 
    return {
      value: this.props.name
    };
  },
  handleChange: function(event) {
    this.setState({value: event.target.value});
  },
  render: function() {
    return (
      <form id="noter-save-form" method="POST">
        <textarea id="noter-text-area" name="textarea" value={this.state.value} onChange={this.handleChange} />
        <input type="submit" value="Save" />
      </form>
    );
  }
});

This is basically a direct copy of the example provided on https://facebook.github.io/react/docs/forms.html

Update for React 16.8:

import React, { useState } from 'react';

const Editor = (props) => {
    const [value, setValue] = useState(props.name);

    const handleChange = (event) => {
        setValue(event.target.value);
    };

    return (
        <form id="noter-save-form" method="POST">
            <textarea id="noter-text-area" name="textarea" value={value} onChange={handleChange} />
            <input type="submit" value="Save" />
        </form>
    );
}

Editor.propTypes = {
    name: PropTypes.string.isRequired
};
Sign up to request clarification or add additional context in comments.

6 Comments

but text is not editable in the textarea. How to resolve this ? @phlie
@Bhanuprathap it should be - what problem are you having?
React component will get a XML from backend and store it in state and passed to textarea through value prop .Programatically alter the xml and somtimes user also modify it. Now on passing through text area value property, user cannot able to modify the xml. @MatthewHerbst
@Bhanuprathap sounds like you should ask a new question for your problem and post your code. You can link to this question in that question for reference.
Old question but the problem @Bhanuprathap faced was due to the property value. If you specify value then it becomes controlled, that means you have to setState (in class component) or useState (hooks). That's why the value from your back-end being passed as props is not rendered. Hope you've already solve it but it could help others.
|
15

As a newbie in React world, I came across a similar issues where I could not edit the textarea and struggled with binding. It's worth knowing about controlled and uncontrolled elements when it comes to react.

The value of the following uncontrolled textarea cannot be changed because of value

 <textarea type="text" value="some value"
    onChange={(event) => this.handleOnChange(event)}></textarea>

The value of the following uncontrolled textarea can be changed because of use of defaultValue or no value attribute

<textarea type="text" defaultValue="sample" 
    onChange={(event) => this.handleOnChange(event)}></textarea>

<textarea type="text" 
   onChange={(event) => this.handleOnChange(event)}></textarea>

The value of the following controlled textarea can be changed because of how value is mapped to a state as well as the onChange event listener

<textarea value={this.state.textareaValue} 
onChange={(event) => this.handleOnChange(event)}></textarea>

Here is my solution using different syntax. I prefer the auto-bind than manual binding however, if I were to not use {(event) => this.onXXXX(event)} then that would cause the content of textarea to be not editable OR the event.preventDefault() does not work as expected. Still a lot to learn I suppose.

class Editor extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      textareaValue: ''
    }
  }
  handleOnChange(event) {
    this.setState({
      textareaValue: event.target.value
    })
  }
  handleOnSubmit(event) {
    event.preventDefault();
    this.setState({
      textareaValue: this.state.textareaValue + ' [Saved on ' + (new Date()).toLocaleString() + ']'
    })
  }
  render() {
    return <div>
        <form onSubmit={(event) => this.handleOnSubmit(event)}>
          <textarea rows={10} cols={30} value={this.state.textareaValue} 
            onChange={(event) => this.handleOnChange(event)}></textarea>
          <br/>
          <input type="submit" value="Save"/>
        </form>
      </div>
  }
}
ReactDOM.render(<Editor />, document.getElementById("content"));

The versions of libraries are

"babel-cli": "6.24.1",
"babel-preset-react": "6.24.1"
"React & ReactDOM v15.5.4" 

1 Comment

Or just onChange={this.handleOnChange.bind(this)}
0

I've recently refactored an app that used the typical value={state} onChange={e => setState(e.target.value)} for my textarea

To now using a useRef hook and removing the value and onChange properties altogether. I update the ref with a custom setter function that updates ref.current.value when I need to update programmatically, but otherwise simply let the user update the textarea value with default html functionality.

I may be re-inventing the wheel a bit, but I expose that ref through React context, and did not want every keystroke to cause re-renders across the app wherever that same context is consumed.

Comments

-2

IMHO all the "textarea content as state" non-sense is not needed - not sure, why react handles it different than the input elements. Anyway, usually one wants to set the content of the textarea if an action occurred, which triggers a re-render of the page/textarea anyway. So the solution I use is to set the defaultValue to a function, which set the textarea content.

E.g. I have an input element with a datalist which is backed by an array of json objects. If a user selects an option from the datalist, the idx of the selected option gets set to the state variable selectedIdx. This in turn causes a re-render of the page. When the re-render finally happens, the defaultValue of the textarea gets re-calculated (because it is an expression/function call) and this in turn gets the corresponding datalist[selectedIdx] object and sets the value of the textarea element to the desired value:

export default function PageFragment(): JSX.Element {
// ...
    const [selectIdx, setSelectIdx] = useState(-1);

    function onInput(e: React.CompositionEvent<HTMLInputElement>) {
        e.preventDefault();
        var ev = e.nativeEvent;
        if (!(('inputType' in ev) && (ev.inputType === 'insertReplacementText')))
            return;
        var idx = getIdx(groups, ev.data.trim());
        if (idx >= 0)
            setSelectIdx(idx);
    }

    useEffect(() => {
        // fetch groups and set selectedIdx if there is only one or pre-selected
    }

    function updateTextarea() {
        var s = selectIdx >= 0 ? groups[selectIdx].desc : ''
        var el = document.getElementById('desc') as HTMLInputElement;
        if (el)
            el.value = s;
        return s;
    }
// ...
    return (
        <div id='group'>
            <div id="kform">
<h1>Gruppenverwaltung</h1>
...
<form action={ACTION_URL} method="post" onSubmit={handleSubmit} acceptCharset='utf-8'>
    <section id='group-selection'>
        <div className="kinput">
            <label htmlFor="group">Gruppe</label>
            <input id="group-selector" name="group" type="search" list={dlID}
                onInput={onInput} />
        </div>
        {createDatalist(dlID, groups)}
    </section>
    <section id='update_group'>
    <div className="kinput">
...
        <label htmlFor="desc">Bemerkung</label>
        <textarea id="desc" name="desc" defaultValue={updateTextarea()}/>
...
    </div>
    </section>

    <div className="buttons">
        <button type="submit">Gruppe aktualisieren</button>
    </div>
</form>
            </div>
        </div>
    );
}

So no onChange handler is needed at all - it is absolutely useless, would be just overhead.

Comments

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.