0

I'm building an autocomplete feature. Everything works as expected except when I reach the end of the input. When I change the value of the input, programatically, the input doesn't scroll/focus on the cursor until I type something.

I tried doing something like this on componentDidUpdate and it worked, but besides being a bit "dirty" I don't want to use the onBlur because I'm closing the autocomplete popup on this event.

setTimeout(() => {
    this.refInput.input.selectionStart = this.refInput.input.selectionEnd = this.state.value.length;
    this.refInput.input.blur();
    this.refInput.input.focus();
}, 1);

How can I achieve this, specially without a setTimeout? If I do it without the setTimeout it doesn't work.

InesM
  • 331
  • 4
  • 16
  • check out this stackoverflow answer [js focus end of text](https://stackoverflow.com/questions/511088/use-javascript-to-place-cursor-at-end-of-text-in-text-input-element) – tstrand66 Jun 17 '19 at 17:00
  • None of the solutions given worked sadly :( – InesM Jun 18 '19 at 08:12

3 Answers3

0

I'd do it with a useEffect Hook

import React, { useEffect } from 'react'

//
//

useEffect(()=>{
    this.refInput.input.selectionStart = this.refInput.input.selectionEnd =  this.state.value.length;
    this.refInput.input.blur();
    this.refInput.input.focus();
 },[this.state.value, this.refInput.input.selectionStart, this.refInput.input.selectionEnd])
Will Jenkins
  • 9,507
  • 1
  • 27
  • 46
  • I'm using a class component for this. Cannot use useEffect. Also I don't want to use blur as the event is used for other things that I don't want necessarily to trigger every time the value changes. – InesM Jun 18 '19 at 08:05
0

I made it worked. Unfortunately it is not very pretty. I still need to use the blur and setTimeout events.

onBlur = () => {
  setTimeout(() => {
    if (this.refInput.input !== document.activeElement) {
      console.log(this.refInput.input.selectionEnd);
      this.setState({ helperVisible: false });
      this.props.clearAutoComplete();
    }
  }, 1);
};

(...)

componentDidUpdate(prevProps, prevState, snapshot) {
  const { value } = this.state;
  if (prevState.value !== value) {
    setTimeout(() => {
      this.refInput.input.selectionStart = this.refInput.input.selectionEnd = this.state.value.length;
      this.refInput.input.blur();
      this.refInput.input.focus();
    }, 0);
}

If anyone has any ideia how to improve this it would be great. Otherwise I'm marking this as the correct answer.

InesM
  • 331
  • 4
  • 16
0

The below should grab the element. focus on it. then move the selection range to the end of the current value. This abides by the desire to avoid blur(). CAVEAT: sometimes it doesn't seem to properly fire in this snippet and in codepen..

(function () {
 const el = document.getElementById('dataList'),
    val = 'this is my value',
  len = val.length;
 el.focus();
  el.value = val;
 setTimeout(function () { el.setSelectionRange(len, len); }, 100);
})();
<input id="dataList">
tstrand66
  • 968
  • 7
  • 11