How to validate pattern matching in textarea?
Asked Answered
S

5

43

When I use textarea.checkValidity() or textarea.validity.valid in javascript with an invalid value both of those always return true, what am I doing wrong?

<textarea name="test" pattern="[a-z]{1,30}(,[a-z]{1,30})*" id="test"></textarea>​

jQuery('#test').on('keyup', function() {
    jQuery(this).parent().append('<p>' + this.checkValidity() + ' ' +
    this.validity.patternMismatch + '</p>');
});

http://jsfiddle.net/Riesling/jbtRU/9/

Sheeran answered 30/11, 2012 at 10:32 Comment(2)
Seems textarea doesn't have the pattern attribute, so chances are browsers will ignore it.Mere
yet i've been using it for years and it works fineTowroy
F
45

HTML5 <textarea> element does not support the pattern attribute.

See the MDN doc for allowed <textarea> attributes.

You may need to define this functionality yourself.

Or follow the traditional HTML 4 practice of defining a JavaScript/jQuery function to do this.

Fetiparous answered 7/9, 2013 at 5:55 Comment(0)
M
14

You can implement this yourself with setCustomValidity(). This way, this.checkValidity() will reply whatever rule you want to apply to your element. I don't think this.validity.patternMismatch can set manually, but you could use your own property instead, if needed.

http://jsfiddle.net/yanndinendal/jbtRU/22/

$('#test').keyup(validateTextarea);

function validateTextarea() {
    var errorMsg = "Please match the format requested.";
    var textarea = this;
    var pattern = new RegExp('^' + $(textarea).attr('pattern') + '$');
    // check each line of text
    $.each($(this).val().split("\n"), function () {
        // check if the line matches the pattern
        var hasError = !this.match(pattern);
        if (typeof textarea.setCustomValidity === 'function') {
            textarea.setCustomValidity(hasError ? errorMsg : '');
        } else {
            // Not supported by the browser, fallback to manual error display...
            $(textarea).toggleClass('error', !!hasError);
            $(textarea).toggleClass('ok', !hasError);
            if (hasError) {
                $(textarea).attr('title', errorMsg);
            } else {
                $(textarea).removeAttr('title');
            }
        }
        return !hasError;
    });
}
Mintun answered 23/1, 2014 at 14:59 Comment(1)
Good answer and thanks for the fiddle. It helped me out!Lordan
X
9

This will enable the pattern attribute on all textareas in the DOM and trigger the Html5 validation. It also takes into account patterns that have the ^ or $ operators and does a global match using the g Regex flag:

$( document ).ready( function() {
    var errorMessage = "Please match the requested format.";

    $( this ).find( "textarea" ).on( "input change propertychange", function() {

        var pattern = $( this ).attr( "pattern" );

        if(typeof pattern !== typeof undefined && pattern !== false)
        {
            var patternRegex = new RegExp( "^" + pattern.replace(/^\^|\$$/g, '') + "$", "g" );

            hasError = !$( this ).val().match( patternRegex );

            if ( typeof this.setCustomValidity === "function") 
            {
                this.setCustomValidity( hasError ? errorMessage : "" );
            } 
            else 
            {
                $( this ).toggleClass( "error", !!hasError );
                $( this ).toggleClass( "ok", !hasError );

                if ( hasError ) 
                {
                    $( this ).attr( "title", errorMessage );
                } 
                else
                {
                    $( this ).removeAttr( "title" );
                }
            }
        }

    });
});
Xyster answered 30/1, 2015 at 5:21 Comment(7)
Yes, that's cleaner. :) Indeed, the pattern attribute in inputs allow ^ and $ in the regexp even though they are implicit.Kubiak
The ^ and $ replace doesn't work. It should be a global (with /g) regexp (with slashes), not a regexp in a string : var patternRegex = new RegExp('^' + pattern.replace(/^\^|\$$/g, '') + '$', 'g');Kubiak
I tried to get this to work on a fiddle looking for an email address on each line. The best I could do add an m modifier and then it would match if there was an email address on ANY line. Still not what I wanted. Yann's first example above worked correctly. How would you use this method instead to solve the problem? Here is the fiddle I created: jsfiddle.net/da1hg19eMansur
@YannDìnendal completely agree, I modified the code accordingly. @BrianLayman you could definitely customize your flags with a m multiline, but this can also be achieved in how you write your regex by taking advantage of the \n\r symbolsXyster
This should be the accepted answer. Even though is an old thread, still very useful information.Oxley
What if you want your regex to disallow single and double quotes? The following breaks the script: [^'"]. Escaping the quotes does not work, either (e.g., [^\'\"]).Governorship
It seems using HTML entities is the workaround. Instead of [^'"], use [^&apos;&quot;].Governorship
N
0

In case there are others who use React-Bootstrap HTML form validation and not jQuery.

This does not explicitly use pattern but it works the same way.

I'm only making some changes from the documentation.

function FormExample() {
  const [validated, setValidated] = useState(false);
  const [textArea, setTextArea] = useState('');
  const textAreaRef = useRef(null);

  const handleSubmit = (event) => {
    const form = event.currentTarget;
    if (form.checkValidity() === false) {
      event.preventDefault();
      event.stopPropagation();
    }

    setValidated(true);
  };

  const isValid = () => {
    // Put whichever logic or regex check to determine if it's valid
    return true;
  };

  useEffect(() => {
    textAreaRef.current.setCustomValidity(isValid() ? '' : 'Invalid');
    // Shows the error message if it's invalid, remove this if you don't want to show
    textAreaRef.current.reportValidity();
  }, [textArea];

  return (
    <Form noValidate validated={validated} onSubmit={handleSubmit}>
      <Form.Row>
        <Form.Group md="4" controlId="validationCustom01">
          <Form.Label>Text area</Form.Label>
          <Form.Control
            required
            as="textarea"
            ref={textAreaRef}
            placeholder="Text area"
            value={textArea}
            onChange={(e) => setTextArea(e.target.value)}
          />
          <Form.Control.Feedback>Looks good!</Form.Control.Feedback>
        </Form.Group>
      </Form.Row>
      <Button type="submit">Submit form</Button>
    </Form>
  );
}

render(<FormExample />);
Novia answered 28/6, 2021 at 3:29 Comment(0)
A
0

All the other answers rely on jQuery/React — here's a vanilla JS one:

const invalid = { pattern: 'a', value: 'b' }
const textarea = Object.assign(document.createElement('textarea'), invalid)

if (textarea.checkValidity()) {
    const input = Object.assign(document.createElement('input'), invalid)

    document.body.addEventListener('input', (e) => {
        if (e.target.matches('textarea[pattern]')) {
            const pattern = new RegExp(`^(?:${e.target.getAttribute('pattern')})$`)

            e.target.setCustomValidity(
                pattern.test(e.target.value)
                    ? ''
                    : input.validationMessage
            )
        }
    })
}
textarea+.validation-msg::after { font-size: 0.8em; }
textarea:not(:invalid) { outline: 3px solid lawngreen; }
textarea:invalid { outline: 3px solid tomato; }
textarea:not(:invalid)+.validation-msg::after { content: "Valid!"; }
textarea:invalid+.validation-msg::after { content: "Invalid!"; }
<p>Enter 0-3 non-empty lines, with optional trailing newline:</p>
<textarea rows="5" pattern="(?:[^\n]+\n?){0,3}"></textarea>
<div class="validation-msg"></div>

The validation message is grabbed from an invalid dummy input element, so it will respect browser defaults, user agent language settings, etc.

Note that it'll handle the typical use case of invalid user input, but it won't handle situations such as programmatically changing the textarea's value, the textarea already being invalid when it's first rendered, etc. A more comprehensive solution would need to handle those scenarios with a MutationObserver or similar.

Annual answered 8/5, 2023 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.