17

How to read the external text change events in react.

The extensions like Grammarly and Auto Text Expander update the text inside textarea, but no react onChange or onInput event is fired after the change. As the result, state is not updated and the condition is inconsistent (different values in textarea and component's state). One way is to read the dom value on submit, but that's not the perfect solution for my scenario, as some other actions depends on the current value of the textarea. Any good solution?

PS: I'm asking for a generic solution. Changing extensions code is not an option.

manish
  • 966
  • 2
  • 11
  • 35
  • 2
    Well, the thing is, the `input` or `textarea` HTML doesn't change on direct modifications of `.value` property employed by those extensions. You'll probably have to poll `document.activeElement.value` periodically if it's a text element. – wOxxOm Oct 24 '16 at 08:28
  • polling not a perfect solution for me. Any other idea? – manish Oct 24 '16 at 08:50
  • Well, since those extensions change the value right after some `keydown` or other hardware event, you can listen to those and poll for a while, then stop. – wOxxOm Oct 24 '16 at 08:52
  • 2
    [How do you get a mutation observer to detect a value change of a textarea?](http://stackoverflow.com/q/12048645/934239) suggests that approaches other than polling are unfortunately unlikely. – Xan Oct 27 '16 at 11:10
  • This works fine for me. Question is not relevant anymore. – Kamlesh Tajpuri Jun 08 '19 at 19:38

3 Answers3

2

I checked this and it works fine for me. Spelling and grammar corrected by Grammarly updates the component state.

<textarea value={this.state.testText} onChange={(e) => {this.setState({testText: e.target.value} )}} />
Kamlesh Tajpuri
  • 482
  • 3
  • 11
0

You can have this kind of problem when you use a jQuery input plugin and the plugin uses .attr method instead of .prop method, which triggers an onChange event. In this case, you need to rely on callback handlers provided by the plugin.

In your case it seems unlikely there's such a callback handler. (It never hurts to check, if the code is available.) Then, the only option seems to be polling, which is ugly but inevitable.

frontsideair
  • 528
  • 3
  • 7
-1

You can add an onchange event listener of all or a specific textarea inside componentDidMount (see the snippet for implementation). This will update the state inside React. The snippet is well addressed with the comment. It should help you!

class KeyTrace extends React.Component {
  constructor(props) {
    super(props)
    this.setValueToState = this.setValueToState.bind(this)
    this.state = {} //initial state
  }
  setValueToState(e) {
   this.setState({
     [e.target.id]: e.target.value //set the new value in the state as {[id]: [value]} pair
   })
  }
  componentDidMount() {
    const textareas = document.querySelectorAll('textarea') //finds all textarea in the DOM
    const textareasArray = [...textareas] //convert the HTML Collection into array
    textareasArray.forEach((el) => { //loop through the array
      if (el.id === 'update') //add onchange listener for specific textareas (optional)
        el.onchange = this.setValueToState //add a event listener
    })

  }
  render(){
    console.log(this.state)
    return false
  }
}

ReactDOM.render(<KeyTrace/>, document.getElementById('react'))
<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 id="non-react">
  Changes will be stored in react state
  <br/>
  <textarea id="update"></textarea>
  <br/>Changes will not be stored in react state
  <br/>
  <textarea id="wont-update"></textarea>
  <br/>
</div>
<div id="react"></div>

PS. You need to blur(click outside the textarea) the textarea to fire the onchange event. Else, you can use onkeypress instead of onchange.

Bogdan Slovyagin
  • 1,109
  • 1
  • 9
  • 23
Pranesh Ravi
  • 18,642
  • 9
  • 46
  • 70