Edsen
Edsen

Reputation: 77

React onChange text input is moving cursor to end of text in input field

I have a bug when I set the value from the state and change the value in a input.

when you write in the input and you try to correct the text the cursor move to the end.

This is my element

<div className="campo">
  <p>Nombre</p>
  <div className="campo-input">
    <input
     type="text"
     name="name"
     value={this.state.name}
     onChange={this.handleInputChangeUpperCase}
     />
  </div>
</div>

This is my function

handleInputChangeUpperCase = (e) => {
    let { name, value } = e.target;
    this.setState({ [name]: value.toUpperCase() });
  };

Working Snippet:

class App extends React.Component {
  state = {
    name: "Ronaldo",
  };
  
  // This is the function
  handleInputChangeUpperCase = (e) => {
    let { name, value } = e.target;
    this.setState({
      [name]: value.toUpperCase(),
    });
  };
  render() {
  
  // This is the Element
    return (
      <div className="campo">
        <p> Nombre </p>
        <div className="campo-input">
          <input
            type="text"
            name="name"
            value={this.state.name}
            onChange={this.handleInputChangeUpperCase}
          />
          {this.state.name}
        </div>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 3

Views: 5867

Answers (4)

Dhaval Jardosh
Dhaval Jardosh

Reputation: 7309

Based on the original answer: https://stackoverflow.com/a/49648061/7427111

class App extends React.Component {
  state = {
    name: "Ronaldo",
  };
  
  handleInputChangeUpperCase = (e) => {
  
    // Here is the addition
    const pointer = e.target.selectionStart;
    const element = e.target;
    window.requestAnimationFrame(() => {
      element.selectionStart = pointer;
      element.selectionEnd = pointer;
    });

    let { name, value } = e.target;
    this.setState({
      [name]: value.toUpperCase(),
    });
  };
  render() {
    return (
      <div className="campo">
        <p> Nombre </p>
        <div className="campo-input">
          <input
            type="text"
            name="name"
            value={this.state.name}
            onChange={this.handleInputChangeUpperCase}
          />
          {this.state.name}
        </div>
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 3

Artem
Artem

Reputation: 129

If you need just toUpperCase as formatting then you can use css instead. It seems the simplest solution is described here https://stackoverflow.com/a/3724990/12868043

Upvotes: 1

HoldOffHunger
HoldOffHunger

Reputation: 20946

To control where the cursor is in an input field, use selectionStart, which indicates where your selected text begins. As long as you don't set selectionEnd, you'll just move the cursor to the desired position.

For instance, let's move to the position "1", just after the first character. For input "123", that should be "1|23"...

document.getElementById('text-area').selectionStart = 1;
document.getElementById('text-area').focus()
  <input id="text-area" type="text" value="123"/>

For your situation, if you want the cursor to move to the start of the string, set .selectionStart = 0. If you want it to go back to where it was originally, save the value with var tempstart = ...selectionStart, and then restore it after you do the data change, .selectionStart = tempstart.

Source: Developer.Mozilla.org: HTMLInputElement.setSelectionRange()

Upvotes: 2

rantao
rantao

Reputation: 1832

That behaviour seems to be happening with .toUpperCase();

handleInputChangeUpperCase = e => {    
    this.setState({ [e.target.name]: e.target.value });
};

If you don't require the text to be upper case immediately on input, I would apply the method outside of the setState

Upvotes: 0

Related Questions