3

I've implemented a custom validation message on my input for the pattern validation rule while leaving the default message for required as is. However, when I do so, once the input becomes invalid, it never becomes valid again, even though I am meeting the pattern criteria.

document.addEventListener("DOMContentLoaded", function () {
  const txtUsername = document.getElementById("UserName");
  txtUsername.oninvalid = function (e)
  {
    const input = e.target;
    if (input.validity.patternMismatch)
    {
      input.setCustomValidity("Usernames cannot contain the @ symbol");
    }
  }
})
<form onsubmit="event.preventDefault(); alert('Form submitted');" action="post">
  <!--pattern regex prohibits use of the @ symbol-->
  <input id="UserName" type="text" pattern="^((?!@).)*$" required />
  <button type="submit">Submit</button>
</form>

JSFiddle demo

When I remove my custom oninvalid event handler, this issue does not occur. What am I doing wrong?

One additional question, though not essential to me resolving this issue: why does Chrome's built in validation pop-up text animate in so slowly and choppy, almost as if there's some sort of performance bottleneck? My machine is powerful and has no issues with any other type of graphical processing.

Chrome validation pop-up animating like I'm trying to run Crysis 2 at max settings on an Intel Pentium III

TylerH
  • 20,799
  • 66
  • 75
  • 101
Jacob Stamm
  • 1,660
  • 1
  • 29
  • 53
  • What browser are you having this issue in? I tried it in Chrome and it works fine. – Jonathon Hibbard Jan 03 '22 at 15:08
  • @JonathonHibbard latest Chrome as well. Same behavior in Firefox. Are you sure you're not getting [this behavior](https://media.giphy.com/media/121gezW5zdv1qXnyPw/giphy.gif)? – Jacob Stamm Jan 03 '22 at 15:19
  • positive. just tried it out myself again to make sure. i only see the warning message you are seeing when i empty it out (which is expected behavior). – Jonathon Hibbard Jan 03 '22 at 15:21
  • @JonathonHibbard any chance you could upload a screen recording like I did? If we're looking at different behavior per platform, then we've got a bigger problem here. I'm using Windows 10, Chrome 96 – Jacob Stamm Jan 03 '22 at 15:26
  • will do. i'm on a mac with Chrome 96 as well. – Jonathon Hibbard Jan 03 '22 at 15:34
  • here is the "correct" link lol: https://media.giphy.com/media/jpVqqtVgOsuqruky4l/giphy.gif – Jonathon Hibbard Jan 03 '22 at 15:39
  • @JonathonHibbard Your recording shows the `required` rule behaving properly, which I already knew about. Have you tried it by triggering invalidity on the `pattern` rule by entering an @ symbol? That's the only one I'm having a problem with. – Jacob Stamm Jan 03 '22 at 15:57

1 Answers1

3

First of all, per MDN:

It's vital to set the message to an empty string if there are no errors. As long as the error message is not empty, the form will not pass validation and will not be submitted.

This agrees with that the HTML standard says:

Suffering from a custom error

When a control's custom validity error message (as set by the element's setCustomValidity() method or ElementInternals's setValidity() method) is not the empty string.

An element satisfies its constraints if it is not suffering from any of the above validity states.

Your sample does not clear the custom error if the form field is determined to be valid. As such, once the field is determined invalid, it stays so for the remainder of the session.

Moreover, you modify custom error only after the field has already been determined invalid. This means the form will still not be submitted even if you clear the message in the same handler.

A better way to accomplish your goal would be to monitor the field in the change event handler for the field and set the custom message there:

document.getElementById('UserName').addEventListener('change', function (ev) {
    const input = ev.target;
    if (input.validity.patternMismatch) {
        input.setCustomValidity("Usernames cannot contain the @ symbol");
    } else {
        input.setCustomValidity("");
    }
}, false);
<form onsubmit="event.preventDefault(); alert('Form submitted');" action="post">
    <!--pattern regex prohibits use of the @ symbol-->
    <input id="UserName" type="text" pattern="^((?!@).)*$" required />
    <button type="submit">Submit</button>
</form>
user3840170
  • 26,597
  • 4
  • 30
  • 62
  • This gets me most of the way there, but I see the reliance on the change event as a potential flaw. What if the input's value is changed programmatically? Also, how is it that the `required` rule still works in your example? I'd imagine that line 6 of your snippet would run if `input.validity.required` were true, preventing the "Please fill out this field" popup from appearing, but it doesn't, so my understanding here must be off base. – Jacob Stamm Jan 03 '22 at 17:30
  • 1
    It’s all in the spec, which describes multiple reasons for why a form field may be considered invalid. If one of the reasons (custom error) doesn’t apply, it doesn’t stop the field from being considered invalid for other reasons (like not being filled at all). The change event not firing for programmatic changes is usually solved by having the changing site fire the event manually. – user3840170 Jan 03 '22 at 18:24
  • I suppose firing the event manually is easy enough of a workaround. It's just disheartening to see that there isn't a simpler way to do something as basic as set a validation rule's error message. It's all very clunky. – Jacob Stamm Jan 03 '22 at 19:10
  • Welcome to frontend development! Also remember that according to the spec, the user agent is not required to _replace_ the message with your own, only to display it somewhere (perhaps along with other validation messages). So it is entirely compliant to display both your custom message and its own generic ‘value does not fit the required pattern’. Really, it’s more meant for things like ‘the user name is already taken’ than this. – user3840170 Jan 03 '22 at 20:56