mr. alex
mr. alex

Reputation: 71

Properly simulate "pattern" attribute with javascript

I'm trying to replicate the html5 pattern attribute with javascript but getting inconsistent results.

The pattern is [a-zA-Z\. \']+

In Chrome, typing "asd 123" does not pass the test.

Using something like

el.value.match(new RegExp(el.pattern))

lets "asd 123" through, obviously because "asd " is a match.

I can solve this particular problem by adding ^ and $ to beginning and end of my pattern, but the question is this - is there some function out there that is implemented exactly as the pattern attribute? Are there other surprises I should expect?

Upvotes: 1

Views: 2827

Answers (3)

MikeM
MikeM

Reputation: 13631

The essence of such a function would likely be something similar to

function validate( el ) {
  // Check hasAttribute to avoid a regex like ^(?:null)$
  return el.value && el.hasAttribute( 'pattern' ) 
    ? new RegExp( '^(?:' + el.getAttribute( 'pattern' ) + ')$' ).test( el.value )
    : null
}

(IE 8+ because of hasAttribute)

Though a proper validation implementation would also have to consider other factors such as the presence of the required attribute. See Data form validation and HTML5 Form shims such as Making HTML5 Form backwards compatible for further detail.

Upvotes: 2

Bergi
Bergi

Reputation: 664434

Are there other surprises I should expect?

Yes. You can look up the pattern attribute in HTML5 spec:

If an input element has a pattern attribute specified, and the attribute's value, when compiled as a JavaScript regular expression with the global, ignoreCase, and multiline flags disabled (see ECMA262 Edition 5, sections 15.10.7.2 through 15.10.7.4), compiles successfully, then the resulting regular expression is the element's compiled pattern regular expression.

That's nice, as it means a JS regex will do exactly as a HTML one.

The compiled pattern regular expression, when matched against a string, must have its start anchored to the start of the string and its end anchored to the end of the string.

Note: This implies that the regular expression language used for this attribute is the same as that used in JavaScript, except that the pattern attribute is matched against the entire value, not just any subset (somewhat as if it implied a ^(?: at the start of the pattern and a )$ at the end).

As you can see, just adding ^ and $ is not enough. If for example somebody entered a disjunction A|B, then ^A|B$ would not be correct - it needs to be ^(A|B)$.

Also you might notice that the pattern attribute does not apply to inputs that are set to multiple.

Is there some function out there that is implemented exactly as the pattern attribute?

You can check out https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills#web-forms for some common polyfill libs/plugins, but I haven't tested any to be standards-compliant.

Upvotes: 3

talemyn
talemyn

Reputation: 7950

Adding ^ and $ is more-or-less implementing it exactly as the pattern attribute. Per the most recent version of the w3c specs for pattern in HTML 5 (http://www.w3.org/html/wg/drafts/html/master/forms.html#the-pattern-attribute):

This implies that the regular expression language used for this attribute is the same as that used in JavaScript, except that the pattern attribute is matched against the entire value, not just any subset (somewhat as if it implied a ^(?: at the start of the pattern and a )$ at the end).

(emphasis added)

Upvotes: 3

Related Questions