3

I'm constructing a form with an input field for a username. I want to restrict the username to a pretty small range of characters using regex, changing the color of the text from red to green based on the validity of the input compared to the regex as the user types.

So far it isn't picking up any characters that aren't valid despite positive testing of the regex.

https://regex101.com/r/XPFy6c/1/

/^[A-Z0-9 -]+$/igm

Here's the code, with a JSFiddle here.

const form = document.querySelector('form');
const input = document.querySelector('input');

const check = /^[A-Z0-9 -]+$/ig;

form.addEventListener("input", e => {
    const checkName = check.test(input.value);
    if(!check) {
        input.classList.add('invalid-name');
        input.classList.remove('valid-name');
    } else {
        input.classList.add('valid-name');
        input.classList.remove('invalid-name');
    }
})
.invalid-name {
  color: red;
}

.valid-name {
  color: green;
}
<form id="form">
    <input class="col-12 edit-name-field" id="name" name="edit-name" maxlength="12" autocomplete="off">
</form>

Update: Although this question is solved, if you try the code you will notice that there remains an issue with the regex alternating true/false. The solution to this problem is here.

Andy
  • 1,422
  • 5
  • 27
  • 43

4 Answers4

5

if you only care about modern browsers, you don't even need JavaScript!

input { border: 2px solid #DDD; }
input:invalid { border-color: red; }
input:valid { border-color: green; }
<input type="text" pattern="^[A-Z0-9 -]{1,12}$">
Chris Barr
  • 29,851
  • 23
  • 95
  • 135
2

In your event listener, you are testing the value alright, however, after that your condition is based on the reference holding the regex not the test result. i.e. check instead of checkName. Since the regex will always evaluate to truthy value, the else part of your condition gets executed. Try your code with following changes:

form.addEventListener("input", e => {
    const checkName = check.test(input.value);
    if(!checkName) {
        input.classList.add('invalid-name');
        input.classList.remove('valid-name');
    } else {
        input.classList.add('valid-name');
        input.classList.remove('invalid-name');
    }
});

Additionally, you should also consider selecting your form, and the input with more specific selectors. Right now your selector basically returns the 'first input field' or 'first form' in the body, this might not always be the element that you expected.

d_shiv
  • 1,670
  • 10
  • 8
2

I think you need to use the checkName variable

    const checkName = check.test(input.value);
    if(!checkName)
Warrenn enslin
  • 1,036
  • 8
  • 11
1

Your code had two problems:

  1. The input event is fired oninput, select and textarea tags, not form. As such, addEventListener was on the wrong element
  2. when you are verifying whether a RegExp works with test, the return value is a boolean indicating if it did, not the RegExp itself. As such, the if statement needed a tweak.

Corrected snippet below:

const form = document.querySelector('form');
const input = document.querySelector('input');

const check = /^[A-Z0-9 -]+$/ig;

input.addEventListener("input", e => {
    const checkName = check.test(input.value);
    if(!checkName) {
        input.classList.add('invalid-name');
        input.classList.remove('valid-name');
    } else {
        input.classList.add('valid-name');
        input.classList.remove('invalid-name');
    }
})
.invalid-name {
  color: red;
}

.valid-name {
  color: green;
}
<form id="form">
    <input class="col-12 edit-name-field" id="name" name="edit-name" maxlength="12" autocomplete="off">
</form>
Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
  • 1
    Regarding the first problem, 'input' event bubbles through the DOM tree. So all input events on child inputs can certainly be caught by attaching an 'input' event handler to the containing form. I haven't tried this in older browsers, but at least in modern browsers this seems to be implemented correctly. – d_shiv May 31 '19 at 13:08