0

I want to validate an input field with regex (replacing all vowels). The input should always be matched against that regex, regardles if typed into or pasted into that field.

I know how to deal with the typing part, but I need help for copy - paste. All vowels should be skipped (e.g.: "abcde" copy --> "bcd" paste)

    $('document').ready(function(){
      var pattern = /[aeiou]/ig;

      $("#input").on("keypress keydown", function (e) {
        if (e.key.match(pattern) !== null) {
          e.preventDefault();
        }
      });
      
      $("#input").on("paste", function (e) {
        var text = e.originalEvent.clipboardData.getData('Text');
        e.preventDefault();

        //TODO... replace all vowels
        console.log(text);
      });
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>

At first i tried to replace them and just set the value with $('#input').val($('#input').val() + copiedValue), but this only works if the cursor is at the end of the input.

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
toffler
  • 1,231
  • 10
  • 27
  • Perhaps [this](https://stackoverflow.com/a/11605436/630530) could help. – Wayne Smallman Mar 09 '22 at 13:46
  • you could even just rely on the change event and catch them all at once... but you should consider that the event fires only when the textbox has lost focus. Otherwise you should rely on the suggestion above where you are invited to use the onpaste event. By the way it's common practice to validate input only when the user has finished with a given field otherwise the logic would be trying to validate the input with any single keystroke and it's usually an unpleasent experience – Diego D Mar 09 '22 at 14:00
  • One needs to subscribe just to the [`input`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event) event. It will cover all the events/use cases the OP is looking for. Of cause already with listening to `keypress` one should think about a [throttled event handling](https://stackoverflow.com/questions/70896882/execute-a-function-not-more-than-once-every-500-milliseconds-while-user-types-co/70899131#70899131). – Peter Seliger Mar 09 '22 at 14:08
  • Thank you for your comments - but for my understanding, all the above suggestions follow the same rules: --> input something --> validate the input --> change the input. I really want to make the validation before something is typed/pasted into – toffler Mar 09 '22 at 14:15
  • Validating e.g. before something new gets pasted into the field does not make any sense, since the newly pasted and (most probably) not valid content immediately invalidates the form fields value. Also the title, the description and the example of your question describes not the scenario of ... _"make the validation before something is typed/pasted into"_. – Peter Seliger Mar 09 '22 at 14:19

2 Answers2

2

A one in all solution subscribes to the input event. In addition to the sanitizing tasks the handler has to take care of reestablishing the input fields exact or most expected cursor/caret position in order to not break the user experience ...

function getSanitizedValue(value) {
  return value.replace(/[aeiou]/ig, '');
}

function handleInput(evt) {
  evt.preventDefault();

  const elmNode = evt.currentTarget;

  const currentValue = elmNode.value;
  const sanitizedValue = getSanitizedValue(currentValue);

  if (currentValue !== sanitizedValue) {
    const diff = sanitizedValue.length - currentValue.length;
    const { selectionStart, selectionEnd } = elmNode;

    elmNode.value = sanitizedValue;

    elmNode.selectionStart =
      (selectionStart + diff > 0) ? selectionStart + diff : selectionStart;
    elmNode.selectionEnd =
      (selectionEnd + diff > 0) ? selectionEnd + diff : selectionEnd;
  }
}

$('document')
  .ready(() => {

    $("#input").on("input", handleInput);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • 1
    "You don't know you need it until you have it" - this solution convinced me, even if i didn't wanted it that way at first – toffler Mar 09 '22 at 14:47
0

One method would be to manipulate the value of the text field from the paste event:

$('document').ready(function(){
      var pattern = /[aeiou]/ig;

      $("#input").on("keypress keydown", function (e) {
        if (e.key.length == 1 && !e.ctrlKey && !e.altKey && e.key.match(pattern) !== null) {
          e.preventDefault()
        }
      });
      
      $("#input").on("paste", function (e) {
        var text = e.originalEvent.clipboardData.getData('Text').replace(pattern, "");
        e.preventDefault();
        let input = e.originalEvent.target,
            start = input.selectionStart,
            end = input.selectionEnd;
        input.value = input.value.substr(0, start) + text + input.value.substr(end);
        input.selectionStart = start + text.length;
        input.selectionEnd = input.selectionStart;
        //TODO... replace all vowels
        console.log(text, input.value);
      });
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='text' id='input'/>
vanowm
  • 9,466
  • 2
  • 21
  • 37
  • Thank you - this is exactely what I was looking for – toffler Mar 09 '22 at 14:33
  • @toffler ... The above implementation prevents a free editing within the input field due to neither being allowed positioning the cursor by by left/right keys nor using the backspace/delete key. – Peter Seliger Mar 09 '22 at 14:42
  • @PeterSeliger your solution is better using single event handler. – vanowm Mar 09 '22 at 14:49