I'm trying to use knockout.validation on a number of parts of a form. Most of this all works fine and can use the built in message appender, but I've got 1 specific field where I need to add the message myself manually to the DOM.
I'm having a real problem getting it working though, because I simply can't get the text to display if there hasn't been a change to the field. I've mocked up a really small example to illustrate as close to the larger form as I can.
The behaviour I'm seeing:
Clicking submit correctly runs the validation (adds a red border around the input) but it doesn't display the error message like it should do.
Typing something into the password box, then emptying it out, then hitting submit works correctly displaying both error message and the red border.
Due to the fact I'm trying to introduce a required field - I can't guarantee that the field has ever been modified, so I need to ensure the first case works. Can anyone see what I'm doing wrong?
ko.validation.init({
registerExtenders: true,
messagesOnModified: true,
insertMessages: true,
decorateInputElement: true,
decorateElementOnModified: false,
errorElementClass: "is-invalid",
messageTemplate: "inline_error"
}, true);
const viewModel = {};
viewModel.submitted = ko.observable(false);
viewModel.clicked = () => { viewModel.submitted(true); };
const onlyIf = ko.computed(() => viewModel.submitted());
viewModel.user = {
password: ko.observable().extend({
required: {
message: `password is required.`,
onlyIf,
}
})
};
ko.applyBindings(viewModel);
.is-invalid {
border: thick solid red;
}
.text-danger {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<div id="domTest">
<button type="button" data-bind="click: clicked">Submit</button>
<input type="password" class="form-control" id="password" placeholder="Password" data-bind="validationOptions:{ insertMessages: false }, textInput: user.password">
<div class="text-danger error-message" data-bind="validationMessage: user.password" />
</div>
In this Github issue, validationMessage does not run on initial binding, stevegreatrex say that you need to change messagesOnModified to false:
messagesOnModified: false
And from the answer to this question Knockout Validation onlyif object no function and pattern validation
(by steve-greatrex) you need to change the onlyIf computed:
viewModel.onlyIf = ko.computed(() => viewModel.submitted());
And then change the property onlyIf in viewModel.user to point to the computed viewModel.onlyIf:
viewModel.user = {
password: ko.observable().extend({
required: {
message: `password is required.`,
onlyIf: viewModel.onlyIf(),
}
})
};
Hope this helps.
ko.validation.init({
registerExtenders: true,
//messagesOnModified: true,
messagesOnModified: false,
insertMessages: true,
decorateInputElement: true,
decorateElementOnModified: false,
errorElementClass: "is-invalid",
messageTemplate: "inline_error"
}, true);
const viewModel = {};
viewModel.submitted = ko.observable(false);
viewModel.clicked = () => { viewModel.submitted(true); };
viewModel.onlyIf = ko.computed(() => viewModel.submitted());
viewModel.user = {
password: ko.observable().extend({
required: {
message: `password is required.`,
onlyIf: viewModel.onlyIf(),
}
})
};
ko.applyBindings(viewModel);
.is-invalid {
border: thick solid red;
}
.text-danger {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<div id="domTest">
<button type="button" data-bind="click: clicked">Submit</button>
<input type="password" class="form-control" id="password" placeholder="Password" data-bind="validationOptions:{ insertMessages: false }, textInput: user.password">
<div class="text-danger error-message" data-bind="validationMessage: user.password" />
</div>
I have a custom method
$.validator.addMethod("lettersandspaces", function(value, element) {
var value = this.elementValue(element).replace(/\s+/g, ' ').trim();
return this.optional(element) || /^[a-zA-Z][a-zA-Z\s]*$/i.test(value);
}, 'Your name may only contain letters');
Here I am trimming whitespace and replacing any repeating whitespaces with only one. I am then validating to make sure there are only letters and spaces.
Is it possible to make it so the trimmed value is submitted with the form instead of what the user entered?
Use the submitHandler and you can make any action before submiting the form ,(form.submit())
See beleow a working snippet
$.validator.addMethod("lettersandspaces", function(value, element) {
var value = this.elementValue(element).replace(/\s+/g, ' ').trim();
return this.optional(element) || /^[a-zA-Z][a-zA-Z\s]*$/i.test(value);
}, 'Your name may only contain letters');
$(document).ready(function () {
$("#form").validate({
rules: {
"name": {
required: true,
minlength: 5,
lettersandspaces: true
},
"age": {
required: true,
}
},
messages: {
"name": {
required: "Please, enter a name"
},
"age": {
required: "Please, enter your age",
}
},
submitHandler: function (form) { // for demo
var newName = $("#name").val().replace(/\s+/g, ' ').trim()
$("#name").val(newName);
$(form).valid();
alert("Name = '"+newName+"'");
// comment return and uncomment form.submit(
return false; //form.submit();
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.0/jquery.validate.min.js"></script>
<script src="//ajax.aspnetcdn.com/ajax/jquery.validate/1.11.0/additional-methods.js"></script>
<form id="form" method="post" action="#">
<label for="name">Name :</label>
<input type="text" name="name" id="name" /><br><br>
<label for="age">Age : </label>
<input type="age" name="age" id="age" /><br><br>
<button type="submit">Submit</button>
</form>
In validation form by jquery. If you want change value input name before validate. Let try:
$('#form').validate({
rules: {
'name': {
normalizer: function(){
return $('#name').val().(/\s+/g, ' ').trim();
}
}
}
})
How do you create a simple, custom rule using the jQuery Validate plugin (using addMethod) that doesn't use a regex?
For example, what function would create a rule that validates only if at least one of a group of checkboxes is checked?
You can create a simple rule by doing something like this:
jQuery.validator.addMethod("greaterThanZero", function(value, element) {
return this.optional(element) || (parseFloat(value) > 0);
}, "* Amount must be greater than zero");
And then applying this like so:
$('validatorElement').validate({
rules : {
amount : { greaterThanZero : true }
}
});
Just change the contents of the 'addMethod' to validate your checkboxes.
$(document).ready(function(){
var response;
$.validator.addMethod(
"uniqueUserName",
function(value, element) {
$.ajax({
type: "POST",
url: "http://"+location.host+"/checkUser.php",
data: "checkUsername="+value,
dataType:"html",
success: function(msg)
{
//If username exists, set response to true
response = ( msg == 'true' ) ? true : false;
}
});
return response;
},
"Username is Already Taken"
);
$("#regFormPart1").validate({
username: {
required: true,
minlength: 8,
uniqueUserName: true
},
messages: {
username: {
required: "Username is required",
minlength: "Username must be at least 8 characters",
uniqueUserName: "This Username is taken already"
}
}
});
});
// add a method. calls one built-in method, too.
jQuery.validator.addMethod("optdate", function(value, element) {
return jQuery.validator.methods['date'].call(
this,value,element
)||value==("0000/00/00");
}, "Please enter a valid date."
);
// connect it to a css class
jQuery.validator.addClassRules({
optdate : { optdate : true }
});
Custom Rule and data attribute
You are able to create a custom rule and attach it to an element using the data attribute using the syntax data-rule-rulename="true";
So to check if at least one of a group of checkboxes is checked:
data-rule-oneormorechecked
<input type="checkbox" name="colours[]" value="red" data-rule-oneormorechecked="true" />
addMethod
$.validator.addMethod("oneormorechecked", function(value, element) {
return $('input[name="' + element.name + '"]:checked').length > 0;
}, "Atleast 1 must be selected");
And you can also override the message of a rule (ie: Atleast 1 must be selected) by using the syntax data-msg-rulename="my new message".
NOTE
If you use the data-rule-rulename method then you will need to make sure the rule name is all lowercase. This is because the jQuery validation function dataRules applies .toLowerCase() to compare and the HTML5 spec does not allow uppercase.
Working Example
$.validator.addMethod("oneormorechecked", function(value, element) {
return $('input[name="' + element.name + '"]:checked').length > 0;
}, "Atleast 1 must be selected");
$('.validate').validate();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.14.0/jquery.validate.min.js"></script>
<form class="validate">
red<input type="checkbox" name="colours[]" value="red" data-rule-oneormorechecked="true" data-msg-oneormorechecked="Check one or more!" /><br/>
blue<input type="checkbox" name="colours[]" value="blue" /><br/>
green<input type="checkbox" name="colours[]" value="green" /><br/>
<input type="submit" value="submit"/>
</form>
Thanks, it worked!
Here's the final code:
$.validator.addMethod("greaterThanZero", function(value, element) {
var the_list_array = $("#some_form .super_item:checked");
return the_list_array.length > 0;
}, "* Please check at least one check box");
You can add a custom rule like this:
$.validator.addMethod(
'booleanRequired',
function (value, element, requiredValue) {
return value === requiredValue;
},
'Please check your input.'
);
And add it as a rule like this:
PhoneToggle: {
booleanRequired: 'on'
}
For this case: user signup form, user must choose a username that is not taken.
This means we have to create a customized validation rule, which will send async http request with remote server.
create a input element in your html:
<input name="user_name" type="text" >
declare your form validation rules:
$("form").validate({
rules: {
'user_name': {
// here jquery validate will start a GET request, to
// /interface/users/is_username_valid?user_name=<input_value>
// the response should be "raw text", with content "true" or "false" only
remote: '/interface/users/is_username_valid'
},
},
the remote code should be like:
class Interface::UsersController < ActionController::Base
def is_username_valid
render :text => !User.exists?(:user_name => params[:user_name])
end
end
Step 1 Included the cdn like
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
Step 2 Code Like
$(document).ready(function(){
$("#submit").click(function () {
$('#myform').validate({ // initialize the plugin
rules: {
id: {
required: true,
email: true
},
password: {
required: true,
minlength: 1
}
},
messages: {
id: {
required: "Enter Email Id"
},
password: {
required: "Enter Email Password"
}
},
submitHandler: function (form) { // for demo
alert('valid form submitted'); // for demo
return false; // for demo
}
});
}):
});
Guys I am using jQuery Validation plugin to validate the Input Text fields...
like this:
$("#formSettings").validate({
rules: {
sta: {
required: true,
},
crs: {
equalTo: "#password"
}
},
messages: {
email: {
required: "Please Provide Your Email Address",
email: "Provide Valid Email Address"
},
});
The issue: I need to match one textfield value with the other, each textfield have comma separated values and they should match before continuing, any idea how can I do that
like if textfield 1 is: 1,2,3,4,5,6 then textfield2 should match.
$('#selector').val().length
Above the basic jQuery version of .length After that you could do an if statement. Here is a brief untested test you try:
<input type="text" value="1,2,3,4,5" id="thing1">
<input type="text" value="1,2,3,4" id="thing2">
<input type="button" name="submit" value="submit" id="submit">
$('#submit').click(function(event){
var thing1 = $('#thing1').val().length;
var thing2 = $('#thing2').val().length;
if (thing1 == thing2) {
return true;
} else {
alert("Contents must have same length");
return false;
}
});
And the fiddle: http://jsfiddle.net/8XQB3/
I am using the jQuery validation plugin. Great stuff! I want to migrate my existing ASP.NET solution to use jQuery instead of the ASP.NET validators. I am missing a replacement for the regular expression validator. I want to be able to do something like this:
$("Textbox").rules("add", { regularExpression: "^[a-zA-Z'.\s]{1,40}$" })
How do I add a custom rule to achieve this?
Thanks to the answer of redsquare I added a method like this:
$.validator.addMethod(
"regex",
function(value, element, regexp) {
var re = new RegExp(regexp);
return this.optional(element) || re.test(value);
},
"Please check your input."
);
Now all you need to do to validate against any regex is this:
$("#Textbox").rules("add", { regex: "^[a-zA-Z'.\\s]{1,40}$" })
Additionally, it looks like there is a file called additional-methods.js that contains the method "pattern", which can be a RegExp when created using the method without quotes.
Edit
The pattern function is now the preferred way to do this, making the example:
$("#Textbox").rules("add", { pattern: "^[a-zA-Z'.\\s]{1,40}$" })
https://cdnjs.com/libraries/jquery-validate
https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.2/jquery.validate.min.js
https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.2/additional-methods.min.js
You can use the addMethod()
e.g
$.validator.addMethod('postalCode', function (value) {
return /^((\d{5}-\d{4})|(\d{5})|([A-Z]\d[A-Z]\s\d[A-Z]\d))$/.test(value);
}, 'Please enter a valid US or Canadian postal code.');
good article here https://web.archive.org/web/20130609222116/http://www.randallmorey.com/blog/2008/mar/16/extending-jquery-form-validation-plugin/
I had some trouble putting together all the pieces for doing a jQuery regular expression validator, but I got it to work... Here is a complete working example. It uses the 'Validation' plugin which can be found in jQuery Validation Plugin
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="http://YOURJQUERYPATH/js/jquery.js" type="text/javascript"></script>
<script src="http://YOURJQUERYPATH/js/jquery.validate.js" type="text/javascript"></script>
<script type="text/javascript">
$().ready(function() {
$.validator.addMethod("EMAIL", function(value, element) {
return this.optional(element) || /^[a-zA-Z0-9._-]+#[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/i.test(value);
}, "Email Address is invalid: Please enter a valid email address.");
$.validator.addMethod("PASSWORD",function(value,element){
return this.optional(element) || /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16}$/i.test(value);
},"Passwords are 8-16 characters with uppercase letters, lowercase letters and at least one number.");
$.validator.addMethod("SUBMIT",function(value,element){
return this.optional(element) || /[^ ]/i.test(value);
},"You did not click the submit button.");
// Validate signup form on keyup and submit
$("#LOGIN").validate({
rules: {
EMAIL: "required EMAIL",
PASSWORD: "required PASSWORD",
SUBMIT: "required SUBMIT",
},
});
});
</script>
</head>
<body>
<div id="LOGIN_FORM" class="form">
<form id="LOGIN" name="LOGIN" method="post" action="/index/secure/authentication?action=login">
<h1>Log In</h1>
<div id="LOGIN_EMAIL">
<label for="EMAIL">Email Address</label>
<input id="EMAIL" name="EMAIL" type="text" value="" tabindex="1" />
</div>
<div id="LOGIN_PASSWORD">
<label for="PASSWORD">Password</label>
<input id="PASSWORD" name="PASSWORD" type="password" value="" tabindex="2" />
</div>
<div id="LOGIN_SUBMIT">
<input id="SUBMIT" name="SUBMIT" type="submit" value="Submit" tabindex="3" />
</div>
</form>
</div>
</body>
</html>
No reason to define the regex as a string.
$.validator.addMethod(
"regex",
function(value, element, regexp) {
var check = false;
return this.optional(element) || regexp.test(value);
},
"Please check your input."
);
and
telephone: { required: true, regex : /^[\d\s]+$/, minlength: 5 },
tis better this way, no?
Extending PeterTheNiceGuy's answer a bit:
$.validator.addMethod(
"regex",
function(value, element, regexp) {
if (regexp.constructor != RegExp)
regexp = new RegExp(regexp);
else if (regexp.global)
regexp.lastIndex = 0;
return this.optional(element) || regexp.test(value);
},
"Please check your input."
);
This would allow you to pass a regex object to the rule.
$("Textbox").rules("add", { regex: /^[a-zA-Z'.\s]{1,40}$/ });
Resetting the lastIndex property is necessary when the g-flag is set on the RegExp object. Otherwise it would start validating from the position of the last match with that regex, even if the subject string is different.
Some other ideas I had was be to enable you use arrays of regex's, and another rule for the negation of regex's:
$("password").rules("add", {
regex: [
/^[a-zA-Z'.\s]{8,40}$/,
/^.*[a-z].*$/,
/^.*[A-Z].*$/,
/^.*[0-9].*$/
],
'!regex': /password|123/
});
But implementing those would maybe be too much.
As mentioned on the addMethod documentation:
Please note: While the temptation is great to add a regex method that checks it's parameter against the value, it is much cleaner to encapsulate those regular expressions inside their own method. If you need lots of slightly different expressions, try to extract a common parameter. A library of regular expressions: http://regexlib.com/DisplayPatterns.aspx
So yes, you have to add a method for each regular expression. The overhead is minimal, while it allows you to give the regex a name (not to be underestimated), a default message (handy) and the ability to reuse it a various places, without duplicating the regex itself over and over.
I got it to work like this:
$.validator.addMethod(
"regex",
function(value, element, regexp) {
return this.optional(element) || regexp.test(value);
},
"Please check your input."
);
$(function () {
$('#uiEmailAdress').focus();
$('#NewsletterForm').validate({
rules: {
uiEmailAdress:{
required: true,
email: true,
minlength: 5
},
uiConfirmEmailAdress:{
required: true,
email: true,
equalTo: '#uiEmailAdress'
},
DDLanguage:{
required: true
},
Testveld:{
required: true,
regex: /^[0-9]{3}$/
}
},
messages: {
uiEmailAdress:{
required: 'Verplicht veld',
email: 'Ongeldig emailadres',
minlength: 'Minimum 5 charaters vereist'
},
uiConfirmEmailAdress:{
required: 'Verplicht veld',
email: 'Ongeldig emailadres',
equalTo: 'Veld is niet gelijk aan E-mailadres'
},
DDLanguage:{
required: 'Verplicht veld'
},
Testveld:{
required: 'Verplicht veld',
regex: '_REGEX'
}
}
});
});
Make sure that the regex is between / :-)
You may use pattern defined in the additional-methods.js file. Note that this additional-methods.js file must be included after jQuery Validate dependency, then you can just use
$("#frm").validate({
rules: {
Textbox: {
pattern: /^[a-zA-Z'.\s]{1,40}$/
},
},
messages: {
Textbox: {
pattern: 'The Textbox string format is invalid'
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/additional-methods.min.js"></script>
<form id="frm" method="get" action="">
<fieldset>
<p>
<label for="fullname">Textbox</label>
<input id="Textbox" name="Textbox" type="text">
</p>
</fieldset>
</form>
This is working code.
function validateSignup()
{
$.validator.addMethod(
"regex",
function(value, element, regexp)
{
if (regexp.constructor != RegExp)
regexp = new RegExp(regexp);
else if (regexp.global)
regexp.lastIndex = 0;
return this.optional(element) || regexp.test(value);
},
"Please check your input."
);
$('#signupForm').validate(
{
onkeyup : false,
errorClass: "req_mess",
ignore: ":hidden",
validClass: "signup_valid_class",
errorClass: "signup_error_class",
rules:
{
email:
{
required: true,
email: true,
regex: /^[A-Za-z0-9_]+\#[A-Za-z0-9_]+\.[A-Za-z0-9_]+/,
},
userId:
{
required: true,
minlength: 6,
maxlength: 15,
regex: /^[A-Za-z0-9_]{6,15}$/,
},
phoneNum:
{
required: true,
regex: /^[+-]{1}[0-9]{1,3}\-[0-9]{10}$/,
},
},
messages:
{
email:
{
required: 'You must enter a email',
regex: 'Please enter a valid email without spacial chars, ie, Example#gmail.com'
},
userId:
{
required: 'Alphanumeric, _, min:6, max:15',
regex: "Please enter any alphaNumeric char of length between 6-15, ie, sbp_arun_2016"
},
phoneNum:
{
required: "Please enter your phone number",
regex: "e.g. +91-1234567890"
},
},
submitHandler: function (form)
{
return true;
}
});
}
we mainly use the markup notation of jquery validation plugin and the posted samples did not work for us, when flags are present in the regex, e.g.
<input type="text" name="myfield" regex="/^[0-9]{3}$/i" />
therefore we use the following snippet
$.validator.addMethod(
"regex",
function(value, element, regstring) {
// fast exit on empty optional
if (this.optional(element)) {
return true;
}
var regParts = regstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
// the parsed pattern had delimiters and modifiers. handle them.
var regexp = new RegExp(regParts[1], regParts[2]);
} else {
// we got pattern string without delimiters
var regexp = new RegExp(regstring);
}
return regexp.test(value);
},
"Please check your input."
);
Of course now one could combine this code, with one of the above to also allow passing RegExp objects into the plugin, but since we didn't needed it we left this exercise for the reader ;-).
PS: there is also bundled plugin for that, https://github.com/jzaefferer/jquery-validation/blob/master/src/additional/pattern.js
This worked for me, being one of the validation rules:
Zip: {
required: true,
regex: /^\d{5}(?:[-\s]\d{4})?$/
}
Hope it helps
$.validator.methods.checkEmail = function( value, element ) {
return this.optional( element ) || /[a-z]+#[a-z]+\.[a-z]+/.test( value );
}
$("#myForm").validate({
rules: {
email: {
required: true,
checkEmail: true
}
},
messages: {
email: "incorrect email"
}
});
Have you tried this??
$("Textbox").rules("add", { regex: "^[a-zA-Z'.\\s]{1,40}$", messages: { regex: "The text is invalid..." } })
Note: make sure to escape all the "\" of ur regex by adding another "\" in front of them else the regex wont work as expected.