Reputation: 6593
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/
Upvotes: 44
Views: 66128
Reputation: 5926
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.
Upvotes: 0
Reputation: 391
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 />);
Upvotes: 0
Reputation: 581
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.
Upvotes: 46
Reputation: 2896
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" );
}
}
}
});
});
Upvotes: 9
Reputation: 1627
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;
});
}
Upvotes: 14