3

I want to intercept the keys typed in one input and change them to others.

For example, I want to simulate typing a 1 each time a key is pressed.

I was thinking to something like this :

           //this example does not work, it will trigger an endless loop

            Array.from(document.querySelectorAll('.onlyOne')).forEach(input =>
                               input.addEventListener('keydown', (event) => {      
                                event.preventDefault();
                                event.srcElement.dispatchEvent(new KeyboardEvent('keydown', { 'key': 49 }));

                            });
                        }
                    );

I canot just add 1 whith event.target.value += 1; cause when there is already text in the input and the cursor is not at the end of the text or the user has selected all text with the mouse , it would not act naturally if text is added at the end of input

Could you help me please?

Pipo
  • 5,170
  • 7
  • 33
  • 66
  • why can't you simply add `1` to the value of the input when any key was pressed? `this.value += "1"` – vsync Jun 30 '18 at 10:40
  • @vsync when there is already text in the input and the cursor is not at the end of the text or the user has selected all text with the mouse , it would not acte naturally if text is added at the end of input – Pipo Jun 30 '18 at 10:49
  • 1
    what about the fact that `[].forEach.call` would run 0 times? – Kutyel Jun 30 '18 at 10:58
  • you should probably check which key was pressed because the way it's coded now will cause in infinite loop (if it ever works, see comment above) – vsync Jun 30 '18 at 11:03
  • @Kutyel I changed this unusual code to make question more intelligible – Pipo Jun 30 '18 at 11:24

1 Answers1

2

By dispatching an event from within the event that causes the same event, you're creating an infinite loop that will cause a Range Error: Maximum call stack size exceeded.

Instead of the event, simply add a 1 to where the cursor is on each keydown.

Array.from(document.querySelectorAll('.onlyOne')).forEach(input =>
  input.addEventListener('keydown', (event) => {
    event.preventDefault();
    event.target.insertAtCaret('1');
}));


HTMLInputElement.prototype.insertAtCaret = function (text) {
  text = text || '';
  if (document.selection) {
    // IE
    this.focus();
    var sel = document.selection.createRange();
    sel.text = text;
  } else if (this.selectionStart || this.selectionStart === 0) {
    // Others
    var startPos = this.selectionStart;
    var endPos = this.selectionEnd;
    this.value = this.value.substring(0, startPos) +
      text +
      this.value.substring(endPos, this.value.length);
    this.selectionStart = startPos + text.length;
    this.selectionEnd = startPos + text.length;
  } else {
    this.value += text;
  }
};
<input class='onlyOne' value="foo">

The HTMLInputElement.prototype.insertAtCaret is taken from this answer: https://stackoverflow.com/a/19961519/3993662

You can change that to a normal function if you don't want to extend the built in's prototype.

baao
  • 71,625
  • 17
  • 143
  • 203
  • thank for answere but when there is already text in the input and the cursor is not at the end of the text or the user has selected all text with the mouse , it would not act naturally if key is added at the end of input – Pipo Jun 30 '18 at 11:13
  • @VivienPipo edited the answer to fulfill the new requirement – baao Jun 30 '18 at 11:39
  • wooo congratulation ! – Pipo Jun 30 '18 at 11:42