-
Notifications
You must be signed in to change notification settings - Fork 0
Implementing validation rules
In DataEntry, validation rules describe how a value must be validated. Validation rules can be defined globally or in specific instances of DataEntry:
Rules defined in Validator.Rules are common across all instances of DataEntry. Below example demonstrates the definition of new global validation rules.
import DataEntry from "dataentry"
// get reference to Validator class and getError utility
const Validator= DataEntry.Validator;
const getError = Validator.getError;
Validator.Rules.mustBeFoo = function (field, value) {
if (value !== "foo") {
// the value is invalid, return an error object using the getError function from Validator
return getError("mustBeFoo", arguments);
}
// the value is valid, return true
return true;
}Instance specific validation rules can also be defined when creating the instance of DataEntry:
import DataEntry from "dataentry"
// get reference to Validator class and getError utility
const Validator = DataEntry.Validator;
const getError = Validator.getError;
var a = new DataEntry({
// specify one additional validation rule for the instance of dataentry:
rules: {
"mustBeFoo": function (field, value) {
if (value !== "foo") {
// the value is invalid, return an error object using the getError function from Validator
return getError("mustBeFoo", arguments);
}
// the value is valid, return true
return true;
}
},
schema: {
// the new rule can then be used with multiple fields defined in the dataentry schema:
"field_a": ["mustBeFoo"],
"field_b": { validation: ["mustBeFoo"], format: ["trim"] },
"field_c": ["mustBeFoo"],
}
})Validation rules can also be defined using the ES6 class syntax, defining new types of DataEntry.
import DataEntry from "dataentry";
// example:
class PaymentsAreaDataEntry extends DataEntry {
// {...} implement here constructor to extend the rules for this kind of DataEntry
// alter `this.validator.rules` to add new rules for a class of DataEntry
}Validation rules are then used in validation schemas (like in example above), to declare the rules for fields by name, or an object with name property:
const dataentry = new DataEntry({
element: wrapper,
marker: DomDecorator,
harvester: DomHarvester,
schema: {
name: {
validation: ["required"],
format: ["cleanSpaces"]
},
year: {
// this example shows a validation rule used by name and one that requires parameters, used by name
validation: ["required", { name: "integer", params: [{ min: 1900, max: 2015 }] }]
},
"only-letters": ["letters"],
"policy-read": ["mustCheck"],
"favored-food": ["required"],
"force-side": ["required"]
}
})DataEntry also support schemas with dynamic validation rules per field, implemented using functions:
/* dataentry schema */
schema: {
propertyOne: {
// This validation is dynamic
validation: function () {
// the function is called in the context of the dataentry
if (someCondition)
return ["required"];
//otherwise:
return ["none"];
}
},
propertyTwo: {
// This validation is static
validation: ["required"]
}
}- Defining asynchronous validation rules
- Example: email validation rule
- Example: phone validation rule
Asynchronous validation rules can be defined using a flag deferred: true, and handling a Promise explicitly:
// custom rule definition
Validator.Rules.myAjaxRule = {
deferred: true, // validation rule is deferred: it returns a Promise explicitly
fn: function (field, value, forced) {
return new Promise(function (resolve, reject) {
var args = arguments;
// for example, an ajax request created using jQuery:
//
$.ajax({
url: "Validation/MyValidationMethod",
type: "POST",
data: {
value: value
}
}).then(function (data) {
// in this example, the server returns JSON: { valid: true / false }
if (data.valid)
return resolve(true);
// else... (read note below in wiki, to know why here we are resolving with error: true!)
resolve({
error: true,
message: "yourErrorKey",
field: field,
value: value,
params: _.toArray(args).splice(2)
});
}).catch(function () {
// ajax request rejection, reject the validation rule promise
// error message for this case is handled by the dataentry
reject();
});
});
};
}Please read the note below about why, by design, validation rules using promise should be resolved also with negative results (validation errors).
Since the official WC3 specification of the ES6 Promise specifies that the rejection should be used only for exceptional situations (ref. Rejections should be exceptional), the DataEntry library always resolve the promises utilized during the validation of fields and forms: returning a value indicating whether a form is valid or not. Rejection should only happen due to bugs in source code or rejection of a validation rule promise (for example, in case a validation rule requires an AJAX request and a web request completes with status 500). Therefore any rejection must be caused by an unhandled exception happened while applying validation logic, and is ultimately related to a bug in the code. In such situations the DataEntry library is designed to decorate the field for which the validation caused exception and consider the whole form invalid.
Validation rules can also be defined using synchronous functions (like the built-in required validation rule), they are automatically wrapped inside a Promise. This is intentional, so programmers can write simpler code for methods that can be resolved synchronously.
This example shows how to implement an email address validation rule:
var getError = Validator.getError;
// add email validation rule:
Validator.Rules.email = {
fn: function (field, value, forced) {
if (!value) return true;
var limit = 40;
var rx = /^(([^<>()[\]\\.,;:\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,}))$/;
if (!value.match(rx) || value.length > limit) {
return getError("invalidEmail", arguments);
}
return true;
}
};This example shows how to implement a phone number validation rule:
var getError = Validator.getError;
Validator.Rules.phone = {
fn: function (field, value) {
if (!value) return true;
if (!/^\s*\+?[0-9\s]+$/.test(value))
return getError("invalidPhone", arguments);
return true;
}
};