Search code examples
javascriptinputkeydowncaret

HTML input: check if user input happened before or after existing value


I need to handle basic users to handle most of edge cases.

I have an input which value is being parsed after typing.

Right now I have problems when a user moves the cursor at the beginning of the input and adds some characters.

What I thought to achieve is:

  1. Determine if input happened before or after existing value
  2. Strip a characters based on that: if before, strip the next character, otherwise strip the first character

The code could look like this:

const myInput = document.querySelector("[my-input]");
const myInputMaxlen = 2;

myInput.addEventListener("input", () => {
  const val = myInput.value;
  const wasBefore = val.selectionStart < val.length;
  if (val.length > myInputMaxlen) {
    myInput.value = wasBefore 
    ? myInput.value.slice(0, myInputMaxlen - 1) 
    : myInput.value.slice(1)
  }

});
<input my-input type="text" maxlength="3" value="" />

The goal is assuming the maxLength of the input is 2, having the input character and one of the already existing characters


Solution

  • Ok, basically the code I wrote is already fine. I added some logic to handle the caret position after editing the string, to make the typing more straight forward.

    Thanks to Mudasir for the tips.

    Here's the final code for generic Javascript:

    const myInput = document.querySelector("[my-input]");
    const myInputMaxlen = 2;
    
    myInput.addEventListener("input", () => {
      const val = myInput.value;
      const caretPos = myInput.selectionStart;
      if (val.length > myInputMaxlen) {
        if(caretPos < val.length) {
          myInput.value = val.slice(0, 1) + val.slice(1, myInputMaxlen);
          caretPos < 2 && setCaretPos(myInput, caretPos);
        }
        else {
          myInput.value = val.slice(1, 1 + myInputMaxlen);
        }
      }
    });
    
    function setCaretPos(ctrl, pos) {
      if (ctrl.setSelectionRange) {
        ctrl.focus();
        ctrl.setSelectionRange(pos, pos);
      } 
      else if (ctrl.createTextRange) {
        var range = ctrl.createTextRange();
        range.collapse(true);
        range.moveEnd('character', pos);
        range.moveStart('character', pos);
        range.select();
      }
      else {
        console.warn("couldn't set caret position");
      }
    }
    <input my-input type="text" value="" maxlength="3" />

    And here's the actual Angular version I was working on:

    
      onHourInput($event: Event): void {
        const t = $event.target as HTMLInputElement;
        if (this.hour.length > this.inputMaxlen) {
          this.hour = t.selectionStart < this.hour.length
            ? this.hour.slice(0, 1) + this.hour.slice(1, this.inputMaxlen)
            : this.hour.slice(1, 1 + this.inputMaxlen);
        }
      }