Closed will-fgmnt closed 5 years ago
Here's a custom validator I wrote for comparing two fields, and a JSFiddle example
https://jsfiddle.net/zoul0813/rukxozdk/ - using _.isEqual for more complex comparisons
https://jsfiddle.net/zoul0813/rukxozdk/4/ - without lodash, doing simple "a" == "b"
check
function isEqualTo(value, field, model) {
if(field.equals == undefined)
return ['invalid field schema, missing `equals` property'];
let a = model[field.equals];
if(value == a)
return [];
return ['strings do not match'];
}
Just add this to your project, then add isEqualTo
to the validator array for the second password. Add an equals
property to the second password fields schema pointing to the first passwords model.
[{
type: 'input',
inputType: 'password',
label: 'Password',
model: 'password',
min: 5,
max: 10,
required: true,
validator: ['string']
},
{
type: 'input',
inputType: 'password',
label: 'Password (Confirm)',
model: 'password2',
min: 5,
max: 10,
required: true,
equals: 'password',
validator: ['string', isEqualTo]
}]
Nice solution
@zoul0813 Thanks. ~Your solution will work but it's worth mentioning you must add the isEqualTo validator on both fields~ EDIT: Actually, no this won't work because validation is still per-field.
Consider the following:
password
field.password2
field.password
field and change mypass to mypass1.The password fields no longer match but no error is shown.
I do strongly believe having form level validation would be a good addition. For example say you had a form with several checkboxes where certain combinations of checks are valid while some combinations are not. Giving each field it's own unique validator might get unwieldly quite quickly as opposed to a single form level validator which accepts the model as it's value and returns an error object if invalid (basically what validate.js does).
@will-fgmnt, the validation function is passed the full form model, and the advanced case of multiple checks would require a custom validator rule anyhow. Whenever validation occurs on a field, the validated event is fired on the form.
I’m just started working on a Validate.js wrapper for VFG this morning, and should have something “usable” tomorrow or the next day as my current project requires some advanced validation as well. I’ll keep you posted on my progress.
@icebob, @will-fgmnt here's a rough draft of what I'm working on.
https://jsfiddle.net/zoul0813/z3up3rwo/
Basically just a Proxy wrapper for ValidateJs, it looks at the field's rules
property. ValidateJs.equality
or any of the other validators works. You can also run multiple ValidateJs validations just by adding them to the "rules" property and calling one of the virtual functions to trigger them all (the rules
property is just passed to validate()
as the constraint). For simple usage, the function called on ValidateJs creates a "functionName": true
constraint (for things like { email: true }
).
This is just a rough draft, and I plan to clean this up quite a bit ... I also hope to be able to get "form-wide validation" working so that when a field is changed, all the fields revalidate. Likely going to stick with the "field by field" validation, but plan to figure out how to get the fields to revalidate themselves by listening for a validation event.
// ValidateJs Proxy for vue-form-generator
// Use ValidateJs.equality, ValidateJs.length, ValidateJs.presence, ValidateJs.format, etc for the field `validator`
let ValidateJsObj = {}
window.ValidateJs = new Proxy(ValidateJsObj, {
get: function get(target, name) {
return function wrapper(value, field, model) {
let constraint = {};
let rules = field['rules'];
if(rules == undefined) {
rules = {};
rules[name] = true;
}
constraint[field['model']] = rules;
let errors = validate(model, constraint);
if(errors != undefined && errors[field['model']])
return errors[field['model']]
return [];
}
}
});
Closing this issue
You can validate the entire form before submitting or using the model-updated
event (just call vfg.validate() inside of your handler), or write custom validation functions. field-by-field validation is really the only way to achieve validation as "form-level" validation would add a large amount of overhead (re-validating everything each time one item is changed).
Here's my final "ValidateJs" wrapper for VFG as well:
// ValidateJs "Plugin" for VFG
import _ from 'lodash';
import validate from 'validate.js';
validate.Promise = Promise;
let ValidateJsObj = {};
window.ValidateJs = new Proxy(ValidateJsObj, {
get(target, name) {
return (value, schema, model) => {
let constraint = {};
let rules = {
[name]: _.get(schema.rules, name, true)
};
constraint[schema.model] = rules;
return validate.async(
model,
constraint,
{
cleanAttributes: false,
format: "flat"
}
).then((errors) => {
return [];
}).catch((err) => {
console.error('ValidateJs:catch', err);
return err;
});
};
}
});
You can then use this in a VFG schema like this:
{
"type": "input",
"inputType": "password",
"autocomplete": "new-password",
"label": "Preferred Password",
"model": "password",
"hint": "Must be 8+ characters and contain at least one uppercase and one number",
"min": 8,
"required": true,
"rules": {
"format": {
"pattern": "^(((?=.*[A-Z])((?=.*[0-9])|(?=.*[!@#\\$%\\^&\\*])))).{8,}",
"flags": "",
"message": "must contain at least one uppercase character and one number or special character"
}
},
"validator": ["string", ValidateJs.format]
},
{
"type": "input",
"inputType": "password",
"autocomplete": "new-password",
"label": "Confirm Password",
"model": "password_confirm",
"required": true,
"rules": {
"equality": "password"
},
"validator": ["required", ValidateJs.equality]
}
Current validation is field level only. It would be great if there was the ability to validate the form as a whole with the error message appear above or below the form (preferably configurable).
My use case is I have a
password
andpasswordConfirm
fields which I want to match. Putting a validator on one or both fields won't work as they are dependant on each other.An alternative approach would be a formOption which runs all field validator whenever any field changes.