I am trying to create a validator which makes a REST call to my server and grabs a value the database. A few problems, when my validator is enabled it only validates that input and not the rest of the constraints. Also, I keep getting this error for the Id length [validate.js] Attribute id has a non numeric value for length, I do not receive this error when I am not using the async validator.
Here is my validator:
validate.validators.myAsyncValidator = function(input, options, key, attributes) {
return new validate.Promise(function(resolve, reject) {
if (!validate.isEmpty(input.value)) {
axios.get('/data-management/verify-data', {
params: {
id: input.value,
filter: options[0]
}
})
.then(function(response) {
if (response.data !== options[1]) resolve(" already exists!");
})
.catch(function(error) {
resolve(": Error, try again.");
});
}
}); };
Here are my constraints:
var constraints = {
email: {
presence: true,
email: true
},
password: {
presence: true,
format: {
// We don't allow anything that a-z and 0-9
pattern: "^[a-zA-Z0-9!##$&()\\-`.+,/\"]*$",
// but we don't care if the username is uppercase or lowercase
flags: "i",
message: "Must contain at least 1 Uppercase, 1 Lowercase, 1 Number, and 1 Special Character"
},
length: {
minimum: 6,
message: "Must be at least 6 characters"
}
},
"confirm-password": {
presence: true,
equality: {
attribute: "password",
message: "^The passwords does not match"
}
},
district: {
presence: true
},
id: {
presence: true,
length: {
minimum: 5,
maximum: 20,
message: "Must be between 6-20 characters"
},
format: {
// We don't allow anything that a-z and 0-9
pattern: "[a-z0-9]+",
// but we don't care if the username is uppercase or lowercase
flags: "i",
message: "can only contain a-z and 0-9"
},
myAsyncValidator: ["signup", false]
}};
And me hooking up my constraints to my form:
var inputs = document.querySelectorAll("input, textarea, select");
for (var i = 0; i < inputs.length; ++i) {
inputs.item(i).addEventListener("change", function(ev) {
// var errors = validate.async(form, constraints).then(function(data) {
// console.log("data");
// });
var obj = this;
var n = this.name;
validate.async(form, constraints).then(function() {
}, function(errors) {
showErrorsForInput(obj, errors[n.valueOf()]);
});
});
}
function handleFormSubmit(form, input) {
// validate the form against the constraints
// var errors = validate.async(form, constraints).then(function(data) {
// console.log("data2");
// });
validate.async(form, constraints).then(function() {
}, function(errors) {
showErrors(form, errors || {});
if (!errors) {
showSuccess();
}
});
I can provide the functons showErrors(), showSuccess(), and showErrorsForInput() if needed.
Thanks!
Found a solution. Checked the ID constraints first, once they were gone, I checked for rest of the constraints. Also added a tokenizer to remove the length error I was receiving.
Here is the updated code:
validate.validators.checkExists = function(input, options) {
return new validate.Promise(function(resolve, reject) {
if (!validate.isEmpty(input.value)) {
axios.get('/data-management/verify-data', {
params: {
id: input.value,
filter: options[0]
}
})
.then(function(response) {
if (response.data !== options[1]) resolve("already exists!");
else resolve();
})
.catch(function(error) {
reject(": Error, try again.");
});
} else resolve();
});
};
// These are the constraints used to validate the form
var constraints = {
email: {
presence: true,
email: true
},
password: {
presence: true,
format: {
pattern: "^[a-zA-Z0-9!##$&()\\-`.+,/\"]*$",
flags: "i",
message: "Must contain at least 1 Uppercase, 1 Lowercase, 1 Number, and 1 Special Character"
},
length: {
minimum: 6,
message: "must be at least 6 characters"
}
},
"confirm-password": {
presence: true,
equality: {
attribute: "password",
message: "^The passwords does not match"
}
},
firstName: {
presence: true
},
lastName: {
presence: true
},
district: {
presence: {
message: "must be selected"
}
}
};
var idConstraints = {
id: {
presence: true,
length: {
minimum: 5,
tokenizer: function(input) {
try {
return input.value;
} catch (e) {
return " ";
}
}
},
checkExists: ["signup", false]
}
};
// Hook up the form so we can prevent it from being posted
var form = document.querySelector("form#signup");
form.addEventListener("submit", function(ev) {
ev.preventDefault();
handleFormSubmit(form);
});
// Hook up the inputs to validate on the fly
var inputs = document.querySelectorAll("input, textarea, select");
for (var i = 0; i < inputs.length; ++i) {
inputs.item(i).addEventListener("change", function(ev) {
var obj = this;
var n = this.name;
validate.async(form, idConstraints).then(function() {
var moreErrors = validate(form, constraints) || {};
showErrorsForInput(obj, moreErrors[n.valueOf()]);
}, function(errors) {
showErrorsForInput(obj, errors[n.valueOf()]);
});
});
}
function handleFormSubmit(form) {
validate.async(form, idConstraints).then(function() {
var errors = validate(form, constraints);
showErrors(form, errors || {});
}, function(errors) {
showErrors(form, errors || {});
if (!errors) {
showSuccess();
}
});
}
Related
I have an Ant Design form with validation <a-from-model> for multiple inputs:
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-model-item has-feedback label="Git Clone Address(.git)" prop="git_address">
<a-input v-model="form.git_address" />
</a-form-model-item>
<a-form-model-item has-feedback label="Number of Modules" prop="module_number">
<a-form-model-item label="Notification Lists(seperated by ,)" prop="maillist">
<a-input v-model="form.maillist" placeholder="johndoe#gmail.com" />
</a-form-model-item>
<a-form-model-item has-feedback label="CI/CD Stages" prop="stage">
<a-checkbox-group v-model="form.stage">
<a-checkbox value="1" name="stage"> Stage 1 </a-checkbox>
<a-checkbox value="2" name="stage"> Stage 2 </a-checkbox>
<a-checkbox value="3" name="stage"> Stage 3 </a-checkbox>
</a-checkbox-group>
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
<a-button type="primary" #click="onSubmit"> Create </a-button>
<a-button style="margin-left: 10px" #click="onCancel"> Cancel </a-button>
</a-form-model-item>
</a-form-model>
Now to submit the form, I need all the validation to pass. This is what export default {data() { looks like:
data() {
let checkPending;
let checkModuleNumber = (rule, value, callback) => {
clearTimeout(checkPending);
if (!value) {
return callback(new Error('Please input the number'));
}
checkPending = setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('Please input digits'));
} else {
if (value < 1) {
callback(new Error('Module number must at least be 1!'));
} else {
callback();
}
}
}, 1000);
};
let checkGitAddress = (rule, value, callback) => {
clearTimeout(checkPending);
checkPending = setTimeout(() => {
if (!value.endsWith(".git")) {
callback(new Error("Please enter clone address that ends with .git!"));
} else {
callback();
}
}, 1000);
};
let checkModuleStage = (rule, value, callback) => {
clearTimeout(checkPending);
checkPending = setTimeout(() => {
if (value.some((x) => x === "2") && value.some((x) => x === "3")) {
callback(
new Error(
"You have selected both Stage 1 and Stage 2. Only one can be selected:"
)
);
} else {
callback();
}
}, 1000);
};
This is what rules looks like:
rules: {
git_address: [
{ required: true, message: "Please input git address", trigger: "change" },
{ validator: checkGitAddress, trigger: "change" },
],
module_number: [
{ required: true, message: "Please input module number", trigger: "change" },
{ validator: checkModuleNumber, trigger: "change" },
],
maillist: [
{ required: true, message: "Please input maillist", trigger: "change" },
],
stage: [
{
type: 'array',
required: true,
message: 'Please select at least one stage',
trigger: 'change',
},
{ validator: checkModuleStage, trigger: "change" },
],
},
Inside methods I defined the following two functions:
onSubmit() {
this.$refs.ruleForm.validate(valid => {
if (valid) {
this.display = true;
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});
},
onCancel() {
this.$refs.ruleForm.resetFields();
},
The problem I have right now is, whenever I changed the input the validation completes really fast. But when I click the submit button, all checks except the last one stuck at the checkPending state, thus the validation can never be completed. Does anyone know what results in this?Thanks so much!
(My wild guess is because all the check function is async but not sure if it's the case and don't know how to resolve it :(()
Turns out all I need to do is to remove all the checkpending functions and only keep the error handeling. async function wound't work in this scenario.
clearTimeout(checkPending);
checkPending = setTimeout(() => {
if ("some condition") {
callback(
new Error("some error")
);
} else {
callback();
}
}, 1000);
How to update a record inside model's method like 'node orm-2' In 'Sequelize'
In orm-2, Just use this.save()
var users = db.define('users',
{
id : { type: 'serial', key: true },
username : { type: 'text', size: 25, unique: true, required: true },
balance : { type: 'integer', defaultValue: 0 },
}, {
timestamp: true,
methods: {
addBalance: function (howMany) {
howMany = Math.abs(howMany);
this.balance += howMany;
this.save(function (err) {
console.log("added money to "+this.username+" : "+howMany);
});
}
}
});
But in Sequelize, I don't know yet
var wallet = sequelize.define('wallet', {
balance : { type: Sequelize.INTEGER, defaultValue: 0, validate: { min: 0 } }
}, {
timestamps: true,
classMethods: {
addBalance: function (howMany) {
howMany = Math.abs(howMany);
this.balance += howMany;
//UPDATE Or SAVE HERE...
}
}
});
Is it have simple command or prefer another methods?
You should place the addBalance method inside instanceMethods, not in classMethods, because you want to operate on a single instance of specified model
instanceMethods: {
addBalance: function(howMany) {
howMany = Math.abs(howMany);
return this.set('balance', this.get('balance') + howMany).save();
}
}
This method would return Promise resolving to current instance of model.
EDIT
Even better solution would be to use instance.increment method
addBalance: function(howMany) {
howMany = Math.abs(howMany);
return this.increment('balance', { by: howMany });
}
It would return the same as the option above.
I have one field which can contain email or mobile (in my case mobile is 8 digits).
I already tried two approaches (both examples doesn't work, because 'element' do not have validate method):
First approach: create custom method and do both validations there, but then I have to create my own email and mobile validation - I couldn't find a way how to reuse jQuery validation rules in new methods. This is what I'd like to have:
jQuery.validator.addMethod("mobileoremail", function(value, element) {
return this.optional(element) ||
element.validate({ rules: { digits: true, rangelength: [8, 8] } }) ||
element.validate({ rules: { email: true } });
}, "Invalid mobile or email");
Second approach: create dependent rules. And also in this case I couldn't find a way how to reuse jQuery validation rules.
{ myRules: {
rules: {
user: {
required: true,
email: {
depends: function(element) {
return !element.validate({ rules: { mobile: true } });
}
},
mobile: {
depends: function (element) {
return !element.validate({ rules: { email: true } });
}
}
}
}
}
}
How about the following validation method...
$.validator.addMethod("xor", function(val, el, param) {
var valid = false;
// loop through sets of nested rules
for(var i = 0; i < param.length; ++i) {
var setResult = true;
// loop through nested rules in the set
for(var x in param[i]) {
var result = $.validator.methods[x].call(this, val, el, param[i][x]);
// If the input breaks one rule in a set we stop and move
// to the next set...
if(!result) {
setResult = false;
break;
}
}
// If the value passes for one set we stop with a true result
if(setResult == true) {
valid = true;
break;
}
}
// Return the validation result
return this.optional(el) || valid;
}, "The value entered is invalid");
Then we could set up the form validation as follows...
$("form").validate({
rules: {
input: {
xor: [{
digits: true,
rangelength: [8, 8]
}, {
email: true
}]
}
},
messages: {
input: {
xor: "Please enter a valid email or phone number"
}
}
});
See it in action here http://jsfiddle.net/eJdBa/
I am using formValidation.io and need to dynamically add a callback type validator within a class so that it can use a class property. The issue is that I initially pass my validator options into a super call that has some form validation procedures. But this means I do not have initial access to class properties.
So to do this I was trying to use updateOption but it definitely does not begin to validate this.
class MyForm extends Form {
var validatorOptions = {
fields: {
phoneNumber: {
validators: {
regexp: {
regexp: Regexp.phone,
message: "Please enter a valid phone number"
}
}
}
}
};
super({
validator: {
options: validatorOptions
}
});
var self = this;
this._cachedPhoneNumbers = [];
var phoneValidatorCallback = {
message: "This number is already in use",
callback: function(value, validator, $field) {
if ($.inArray(value, self._cachedPhoneNumbers) > -1)
return false;
return true;
}
}
// ref to validator is definitely valid!
this.validator.updateOption('phone', 'callback', 'callback', phoneValidatorCallback);
}
Here is the answer. I simply misused the function.
class MyForm extends Form {
var validatorOptions = {
fields: {
phoneNumber: {
validators: {
regexp: {
regexp: Regexp.phone,
message: "Please enter a valid phone number"
},
callback: {
message: 'This number is in use',
callback: function() {
return true;
}
}
}
}
}
};
super({
validator: {
options: validatorOptions
}
});
var self = this;
this._cachedPhoneNumbers = [];
function phoneValidatorCallback(value, validator, $field) {
if ($.inArray(value, self._cachedPhoneNumbers) > -1)
return false;
return true;
}
// ref to validator is definitely valid!
this.validator.updateOption('phone', 'callback', 'callback', phoneValidatorCallback);
}
I have a form to change password. I need to validate the old password. But jquery addMethod is always return false in Meteor.call. How to make it workable. Or is there any way? My bellow code will be more details about my issue.
$.validator.addMethod( 'checkPassword', ( oldpassword ) => {
var digest = Package.sha.SHA256(oldpassword);
Meteor.call('checkPassword', digest, function(err, result) {
var res = result.error != null; // even if this is "true", error message is visible.
return res;
});
});
$( "#changepassword" ).validate({
rules: {
oldpassword: {
required: true,
checkPassword: true
}
},
messages: {
oldpassword: {
required: "Please enter your Old Password",
checkPassword: "Password doesnt match!!!" //this message is visible all the time.
} }
});
Here is my method call
Meteor.methods({
checkPassword: function(digest){
if (Meteor.isServer) {
if (this.userId) {
var user = Meteor.user();
var password = {digest: digest, algorithm: 'sha-256'};
var result = Accounts._checkPassword(user, password);
return result;
}
}
}
});
here the meteor package