Search code examples
reactjsredux-form

Simulate pasting a value into a field using React (2/ redux-form)


Looking for some tips on what I could do to achieve this. Basically, I have an input with buttons near it for quick entry. When the buttons are clicked, it needs to simulate pasting a value into the text field where the user's cursor is located. Also if there is something highlighted it should replace it with the text entered.

I am using redux-form's change action to update the value right now, which works for adding onto the end - but does not give the effect I am looking for.


Solution

  • What you're trying to achieve here goes against how the browser behaves by default. Clicking on a button will cause an input to lose its focused state along with the cursor position. You can get around this, of course, by overloading your component state but as you add more inputs and logic it might become too much to manage.

    For the sake of argument, I'm posting one possible solution here, it's not something I'd ship to production unless there was a very good reason for it.

    You'll need to store the input value in state, this is what does, I'm using plain component state in my example. Whenever your focus moves from the input to the button (blur event) you get the input selectionStart and selectionEnd and make a state update replacing what's between them in the original input value with your custom value.

    Like I said, adding multiple inputs to the mix will complicate matters as you'll need to tie each input ref to a state key.

    class MyForm extends React.Component {
      constructor() {
        super();
        
        this.state = {
          inputValue: ''
        }
      }
      
      render() {
        return <form>
          <input 
            value={this.state.inputValue}
            ref={e => this.input = e} 
            onBlur={this.onBlurInput}
            onChange={this.onInputChange}
          />
          <br />
          <button 
            ref={e => this.button = e} 
            type="button" 
            onClick={this.onAppend}
          >
            Append to cursor
          </button>
        </form>;
      }
      
      onBlurInput = (e) => {
        // `e.target` is the input being blurred here
        const stringToInsert = 'Hello World';
        const {inputValue} = this.state;
        const {selectionStart, selectionEnd} = e.target;
        
        // We've clicked the button and the input has become blurred
        if (e.relatedTarget === this.button) {
          const newInputValue = inputValue.substring(0, selectionStart) + 
                                stringToInsert + 
                                inputValue.substring(selectionEnd);
          
          this.setState({
            inputValue: newInputValue
          })
        }
      }
      
      onAppend = (e) => {
        // Re-focus the input
        this.input.focus();
      }
      
      onInputChange = (e) => {
        this.setState({
          inputValue: e.target.value
        });
      }
    }
    
    ReactDOM.render(<MyForm />, document.getElementById('root'));
    <link href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.2/normalize.min.css" rel="stylesheet" type="text/css" />
    <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="root"></div>