skip to Main Content

My problem is so simple and yet, i can’t figure out what going on.

My scenario:

  • Vanilla JS and HTML
  • A text input has an onChange event for validation. Every time you press a key a regex analises it and if its an special char it makes the input invalid.
  • Regex: /[!@#$%^&*()_+-=[]{};':"\|,.<>/?~]/g

Codepen with example

And the snippet below:

const noSymbolsRegex = /[`!@#$%^&*()_+-=[]{};':"\|,.<>/?~]/g;
const onChange = (event) => {
  const value = event.target.value;
  const hasError = noSymbolsRegex.test(value);
  console.log(
    `Value => ${value} n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
  );
  if (hasError) {
    console.log("<< == hasError");
    document.querySelector("#my-test-input").dataset.valid = "false";
  } else {
    document.querySelector("#my-test-input").dataset.valid = "true";
    console.log("<< == DOES NOT haveError");
  }
};
const input = document.querySelector("#my-test-input");
input?.addEventListener("keyup", onChange);
input[data-valid="false"] {
  background-color: red;
}

input[data-valid="true"] {
  background-color: green;
}
<label for="test">Test input</label>
<input name="test " type="text" id="my-test-input" data-valid="true">

Expected behavior

Every time you insert a special char the regex must test it and return if its valid.

Actual behavior

  • Randomly, but specially if you enter many special chars and then begins to erase them, regex test the input and returns that it haven’t the special chars.
  • Pressing special keys like Control or Alt toggle the valid/invalid state.

I suppose the problem is the regex but i don’t understand why it works only some times

2

Answers


  1. Yes, problem is in regex
    You can try below regex

    /[ `!@#$%^&*()_+-=[]{};':"\|,.<>/?~]/
    
    const noSymbolsRegex = /[ `!@#$%^&*()_+-=[]{};':"\|,.<>/?~]/;
    const onChange = (event) => {
      const value = event.target.value;
      const hasError = noSymbolsRegex.test(value);
      console.log(
        `Value => ${value} n Has forbidden symblos ? ${hasError ? "YES" : "NO"}`
      );
      if (hasError) {
        console.log("<< == hasError");
        document.querySelector("#my-test-input").dataset.valid = "false";
      } else {
        document.querySelector("#my-test-input").dataset.valid = "true";
        console.log("<< == DOES NOT haveError");
      }
    };
    const input = document.querySelector("#my-test-input");
    input?.addEventListener("keyup", onChange);
    input[data-valid="false"] {
      background-color: red;
    }
    
    input[data-valid="true"] {
      background-color: green;
    }
    <label for="test">Test input</label>
    <input name="test " type="text" id="my-test-input" data-valid="true"></input>
    Login or Signup to reply.
  2. This is a refactored regex, and no need for the global flag with test().

    Edit 3/10/23, using the global flag //gin test() and exec() JS functions sets the regex objects lastindex member to the last matched position.
    Thats why the repeated runs of this regex cause it to flip flop the match
    from the strings beginning, to the strings end where one matched and the other didn’t.

    const noSymbolsRegex = /[!-/:-@[-`{-~]/;
    

    Works but your onChange event handler doesn’t seem to get called on a paste from context menu.
    If doing keystrokes ctrl-v works fine. But if from the context menu, doesn’t get called.

    Extra info [!-/:-@[-`{-~] matches these 32 codepoints !"#$%&'()*+,-./:;<=>?@[]^_`{|}~
    These codepoints correspond to [x21-x7e](?<![^W_]) as well.

    Info on JS lastindex regex member can be founh here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex

    Excerpt:

    The lastIndex data property of a RegExp instance specifies the index at 
    which to start the next match.   
    
    This property is set only if the regular expression instance used the g flag
    to indicate a global search, or the y flag to indicate a sticky search.
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search