JavaScript native form abilities [duplicate] - javascript

I want to know if there is any way to programmatically show a HTML validation error, using a JavaScript function.
This is useful for scenarios where email duplication has to be checked. For example, a person enters an email, presses the Submit button, and then has to be notified that this email is already registered or something.
I know there are other ways of showing such an error, but I wanted to display it in the same way as how the validation error messages are shown (e.g. invalid email, empty field, etc.).
JSFiddle: http://jsfiddle.net/ahmadka/tjXG3/
HTML Form:
<form>
<input type="email" id="email" placeholder="Enter your email here..." required>
<button type="submit">Submit</button>
</form>
<button id="triggerMsg" onclick="triggerCustomMsg()">Trigger Custom Message</button>
JavaScript:
function triggerCustomMsg()
{
document.getElementById("email").setCustomValidity("This email is already used");
}
The above code sets the custom message, but its not automatically shown. It's only shown when the person presses the submit button or something.

You can now use the HTMLFormElement.reportValidity() method, at the moment it's implemented in most browsers except Internet Explorer (see Browser compatibility at MDN). It reports validity errors without triggering the submit event and they are shown in the same way.

var applicationForm = document.getElementById("applicationForm");
if (applicationForm.checkValidity()) {
applicationForm.submit();
} else {
applicationForm.reportValidity();
}
reportValidity() method will trigger HTML5 validation message.

This question was asked over a year ago, but it's a good question that I recently encountered as well...
My solution was to use JavaScript to create an attribute (I went with "data-invalid") on the <label> of each <input>, <select> and <textarea> containing the validationMessage.
Then some CSS...
label:after {
content: attr(data-invalid);
...
}
... displays the error message.
Limitations
This only works provided each element has a label. It will not work if you put the attribute on the element itself, because <input> elements cannot have :after pseudo elements.
Demo
http://jsfiddle.net/u4ca6kvm/2/

As mentoned by #Diego you can use form.reportValidity();
To support IE and Safari include this polyfill, it just works:
if (!HTMLFormElement.prototype.reportValidity) {
HTMLFormElement.prototype.reportValidity = function() {
if (this.checkValidity()) return true;
var btn = document.createElement('button');
this.appendChild(btn);
btn.click();
this.removeChild(btn);
return false;
}
}

Related

Why are custom validation messages causing my HTML form elements to stay invalid?

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.
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>

Problem with getting javascript answer after a subscription button

I'm doing a form with one field: a password form. When I submit it, I just want the JavaScript to tell the user if the password is the good one or if he has to try again.
Here's my code:
var x = document.forms["CodeForm"]["email"].value;
if (x == "MAX") {
$message._show('success', '✅ Code Correct !');
} else {
$message._show('failure', '❌ Code Incorrect !');
}
As you see, the "succes" and "failure" parts are for my CSS class who tells the script the color of the text just after. Now, my problem is when I enter anything, the "if" part works and it says "Code Incorrect !" in red (as I want) but if I enter the good code just after, it says "Code Correct" but in red, and not in green as it is in the CSS class "success". When I enter the good code first (after reloading the page) then it's in green.
If you wanna try it, here's my website, and the good code is "MAX" : http://enigma-door.000webhostapp.com
Here are the html code for the form and the _show method:
<form name="CodeForm" id="signup-form" method="post" action="#">
<input type="text" name="email" id="email" placeholder="Code" />
<input type="submit" value="Valider" />
</form>
$message._show = function(type, text) {
$message.innerHTML = text;
$message.classList.add(type);
$message.classList.add('visible');
window.setTimeout(function() {
$message._hide();
}, 3000);
};
Inside your $message._show method please remove the existing class then it will work.$message.classList.remove("failure");
Since your failure css class is not removed it is having high specificity and overriding for success
It's impossible to know for sure without seeing the _show method, but it sounds like perhaps you're not removing the .failure class when you're adding the .success class.
The way to find out is to inspect the html using chrome's dev tools and see what classes your input has. That will tell you why it's red.

on('submit' works when clicking the <button> but not when pressing enter on an input field

I'm using on('submit') to detect when the form was submitted, but it only works when the user clicks on the submit button.
I use a <button> tag so I can put an image inside the button. I know I could use an input with type="submit" and use CSS it with the image, but I'd like to know the alternative jQuery way.
I was thinking doing an or comparison, for example on('submit') OR when user presses enter on any of the input field, but how should I do that?
$('#form').on('submit', function (e) {
e.preventDefault();
var email = $('#email').val();
function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
});
<form id="form">
<input id="email" maxlength="64" name="EmailEDIT" type="text" width="100">
<button id="submitBtn"><img height="30" src="images/fx_demo_button.png" width="74"></button>
</form>
If the user presses enter in one of the field, the form will submit. It will trigger the same event as the button does. If this does not occur, something's up in your code.
You commented that your code doesnt work, but it does: http://jsfiddle.net/B5pZ4/
All I've added was alert(1); the rest is your code from this topic
You define your function in the eventhandler, might be better to seperate that, just in case you want to use that function again (or alter it a bit and use it in two situations).
If you seperate it in your code, it'll make more sense, I also think this is the problem you're having:
http://jsfiddle.net/B5pZ4/1/
You can actually make your code work with just one line. You create the function in your eventhandler (which, in this case, should be considered bad practice!), but you never call it. Either remove the function declaration, or add this under the function:
return validateEmail( email ); // THIS IS BAD PRACTICE AS FIX!
A tip: if you're working in html5, you can use this and the browser will do validating for you:
<input type="email" />
You need to insert an invisible input type submit for this to work.

Custom form validation function on element with html 5

For a custom image selection tool I would like to create form validation based on html 5 form validation.
For example my form consists of the following elements:
<form class="cms-form" action="">
<table width="800">
<tr>
<td width="30%">Name:</td>
<td><input type="text" name="name" class="cms-input-text" maxlength="127" /></td>
</tr>
<tr>
<td>Image:</td>
<td><textarea name="icon" class="cms-input-file" data-file-resource="images" data-options="{"min":1,"max":3}">/location-to-image.png</textarea></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Next"/></td>
</tr>
</table>
</form>
I have a Javascript that changes the textarea (.cms-input-file) into some html to add images and hides the original textarea.
It looks something like this:
<textarea name="icon" class="cms-input-file" data-file-resource="images" data-options="{"min":1,"max":3}" style="display: none;">/location-to-image.png</textarea>
<ul class="cms-input-file-list">
<li class="cms-input-file-item" data-image="/location-to-image.png">
<img src="/location-to-thumb.png" alt="" class="cms-input-file-item-thumbnail"/>
<span class="cms-input-file-item-title">location to image</span>
</li>
<li class="cms-input-file-add">Add</li>
</ul>
Since I have allot of existing forms using html5 form validation I would like to validate this element using the default form validation within html5 supported browsers, but using a hopefully existing event.
I'm looking for something like this:
$('.cms-input-file').on('customValidateFunction', function () {
var options = $(this).data('options');
if($(this).find('> li.cms-input-file-item').length < options.min)
{
return [false, 'Add more images.'];
}
if($(this).find('> li.cms-input-file-item').length > options.max)
{
return [false, 'Remove some images.'];
}
return true;
});
Does anyone know if something like this is possible using default html 5 events or how would I go about adding this event to the submit event? To actually trigger the default browser validation look and feel.
-- edit --
So far I have made an attempt to get this result using a div element which hides the original element. But now I need to add a pattern to the element to match according to my options. Is this possible?
Current progress: http://jsfiddle.net/jeffreydev/YyEVu/
If I understand correctly what you need, I think you can achieve what you are trying to do using the pattern attribute of any input element.
I've created a very simple form in jsfiddle illustrating this.
The idea is that you update the value of your input with whatever data you have in your model when adding or removing images. The example, just adds one letter f per icon. Then, you can create a regex to match the expected valid results. In the example, pattern="f{1,3}" means that to be valid, the content can be "f", "ff", or "fff" but nothing else, which means that it'll only accept from one to three files to be sent.
You would be using just default html5 form validation, but you may need a bit of tweaking to get it working.
However, if you try this way, you should keep a couple of things in mind:
As explained in the specs, the patttern is compiled as a JavaScript regular expression with the global, ignoreCase, and multiline flags disabled
Setting the disabled property of your input so that the user can't change it would take it out of the form, and thus it won't be validated
Applying certain styles as *display:none" to the input element can cause errors when the validation fails and the browser tries to gain focus on the element.
I hope you this helps
You can install a submit handler on the <form>, and dispatch a custom event from there.
That will look something like this:
$('form.cms-form').on('submit', function(evt) {
var frm = $(this);
var allElements = $(this.elements);
$('#errors').empty();
var errors = [];
var arg = {
reportValidationError : function( msg ) {
errors.push(msg);
},
form : this
};
console.log("all elements: ", allElements);
allElements.trigger('customValidate', [ arg ]);
if( errors.length !== 0 ) {
showValidationErrors(errors);
return false;
}
return true;
});
Then, you can "hook" the customValidate event, and install your own logic...
$('textarea[name=icon]').on('customValidate', function(evt, reporter) {
var options = $(this).data('options');
// ... your validation here ...
// for example:
var txt = $(this).val();
if( txt.length < options.min || txt.length > options.max ) {
reporter.reportValidationError('error: "icon" min/max exceeded!');
}
})
Here's an example at jsFiddle.
Edit
You can style the error reporting, and tweak the code, to look and behave however you want it to. Here's an example.
A very good jquery plugin to validate your forms is Mike Alsup one's.
You will find it here: http://jquery.malsup.com/form/
It is documented, ajax compatible.
It can do serialization for one field or for all fields inside the form, so it is a big advantage regarding your problem you could need to handle fields validation and error logic with your forms.
You could add the blockUI plugin of the same author to enhance user's experience, and don't have to manage double submission of the form when javascript is enabled.
http://jquery.malsup.com/block/
Answer from 2022: Yes, it is possible without jQuery etc.
Most browsers support Constraint Validation API (even IE 11 according to "caniuse")
The recommended practice is to listen to input/submit events and then set validity flags on the input-box.
<form>
<input type="text" required id="answer">
<input type="submit">
</form>
Validation JS:
const nameInput = document.querySelector("#answer");
const form = document.querySelector("form");
function validate(e) {
if (nameInput.value == "42") { //correct!
nameInput.setCustomValidity(""); // empty means "no error"
}
else {
nameInput.setCustomValidity("Wrong answer!"); //show error text
e.preventDefault(); //prevent form submit
}
}
nameInput.addEventListener("input", validate);
form.addEventListener("submit", validate);
The input event fires even when the value is changed programmatically
P.S. Codepen to play with: https://codepen.io/jitbit/pen/XWYZjXO

Disabling form password autocompletion but not other fields

I know you can disable the autocomplete on a form by setting autocomplete="off" on the form itself.
The problem I have is, I want to prevent the browser from populating the password field but do not want to disable username or other fields.
The other thing to consider is legacy data. Using autocomplete="off" on the form (or even the field itself) does not prevent existing users with saved passwords from getting a free-pass. Or ones that use web inspector, change the value of autocomplete and submit, allowing themselves to save the password.
I know it is possible to change the password field name attribute to a random/new one on every visit. Regretfully, I am working with a java/spring back-end and I am being told this is NOT easily manageable without a huge refactor/override.
How would you architect this? How would you enforce that the field always starts empty? There is no consistent way for browsers to event notify you of pre-population by a password manager - some may fire an onChange, others may not.
I guess I can move fields around with javascript and build the real form on the fly and submit it but once again, this will have implications with spring security and validations etc. Any other ideas?
you can made a temp variable when onFocus is call to set a variable to true ( like userFocus )
and on the onChange attribut but a short code for reseting "value" to NULL if userFocus== false) kind of overkilling imo but migth work
EDIT
function reset()
{
if (document.getElementById("hidden").value!=" ")
{
document.getElementById("demo").value=" ";
}
else;
}
function getfocus()
{
document.getElementById("hidden").value=" ";
}
else;
}
<input type="password" id="pwd" onchange="reset()" onfocus="getfocus()"/>
<input type="hidden" id="hidden" value="not focus"/>
I had to find this solution for IE 11 (since it ignores the autocomplete attribute). It works fine in other browsers. Really more of a work around, but it works.
https://stackoverflow.com/a/20809203/1248536
I was recently faced with this problem, and with no simple solution since my fields can be prepopulated, I wanted to share an elegant hack I came up with by setting password type in the ready event.
Don't declare your input field as type password when creating it, but add a ready event listener to add it for you:
function createSecretTextInput(name,parent){
var createInput = document.createElement("input");
createInput.setAttribute('name', name);
createInput.setAttribute('class', 'secretText');
createInput.setAttribute('id', name+'SecretText');
createInput.setAttribute('value', 'test1234');
if(parent==null)
document.body.appendChild(createInput);
else
document.getElementById(parent).appendChild(createInput);
$(function(){
document.getElementById(name+'SecretText').setAttribute('type', 'password');
});
};
createSecretTextInput('name', null);
http://jsfiddle.net/N9F4L/

Categories