NumberValidator class
The NumberValidator class ensures that a String represents a valid number. It can ensure that the input falls: - within a given range (specified by minValue and maxValue), - is an integer (specified by domain), - is non-negative (specified by allowNegative), - does not exceed the specified precision.
The validator correctly validates formatted numbers (e.g., "12,345.67") and you can customize the thousandsSeparator and decimalSeparator properties for internationalization.
class NumberValidator extends WidgetValidator {
static const String INTEGER = "integer";
static const String DOUBLE = "double";
/**
* Specifies whether negative numbers are permitted.
* Allowed by default.
*/
bool allowNegative;
/**
* The character used to separate the whole from the fractional part of the
* number. Cannot be a digit and must be distinct from the [thousandsSeparator].
* By default equals "."
*/
String decimalSeparator;
/**
* Type of number to be validated.
* Permitted values are [NumberValidator.INTEGER] and [NumberValidator.DOUBLE].
* By default equals [NumberValidator.DOUBLE].
*/
String domain;
/**
* Maximum value for a valid number. A value of null means there is no maximum.
*/
num maxValue;
/**
* Minimum value for a valid number. A value of null means there is no minimum.
*/
num minValue;
/**
* The maximum number of digits allowed to follow the decimal point.
* Can be any nonnegative integer.
*/
int precision;
/**
* The character used to separate thousands in the whole part of the number.
* Cannot be a digit and must be distinct from the [decimalSeparator].
*/
String thousandsSeparator;
/**
* Error message when the decimal separator character occurs more than once.
* By default equals "The decimal separator can occur only once."
*/
String decimalPointCountError;
/**
* Error message when the value exceeds the [maxValue] property.
* By default equals "The number entered is too large."
*/
String exceedsMaxError;
/**
* Error message when the number must be an integer, as defined by the
* [domain] property.
* By default it's equals "The number must be an integer."
*/
String integerError;
/**
* Error message when the value contains invalid characters.
*
* By default it equals "The input contains invalid characters."
*/
String invalidCharError;
/**
* Error message when the value contains invalid format characters, which
* means that it contains a digit or minus sign (-) as a separator character,
* or it contains two or more consecutive separator characters.
*
* By default it equals "One of the formatting parameters is invalid."
*/
String invalidFormatCharsError;
/**
* Error message when the value is less than [minValue].
*
* By default it equals "The amount entered is too small."
*/
String lowerThanMinError;
/**
* Error message when the value is negative and the [allowNegative]
* property is [false].
*
* By default it equals "The amount may not be negative."
*/
String negativeError;
/**
* Error message when the value has a precision that exceeds the value defined
* by the precision property.
*
* By "default" it equals "The amount entered has too many digits beyond the decimal point."
*/
String precisionError;
/**
* Error message when the thousands separator is in the wrong location.
*
* By default it equals "The thousands separator must be followed by three digits."
*/
String separationError;
NumberValidator(Widget widget, {
this.allowNegative:true,
this.decimalPointCountError:"The decimal separator can only occur once.",
this.decimalSeparator:".",
this.domain:NumberValidator.DOUBLE,
this.exceedsMaxError:"The number entered is too large.",
this.integerError:"The number must be an integer.",
this.invalidCharError:"The input contains invalid characters.",
this.invalidFormatCharsError:"One of the formatting parameters is invalid.",
this.lowerThanMinError:"The amount entered is too small.",
this.maxValue:null,
this.minValue:null,
this.negativeError:"The amount may not be negative.",
this.precision:-1,
this.precisionError:"The amount entered has too many digits beyond the decimal point.",
this.separationError:"The thousands separator must be followed by three digits.",
this.thousandsSeparator:","}) : super(widget);
/**
* Override of the base class [doValidation()] method
* to validate a number.
*
* <p>You do not call this method directly;
* Flex calls it as part of performing a validation.
* If you create a custom Validator class, you must implement this method. </p>
*
* @param value Object to validate.
*
* @return An Array of ValidationResult objects, with one ValidationResult
* object for each field examined by the validator.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
/**
* Executes the validation logic of this validatorto validate a number.
* Invalid result returns an List of [ValidationResult] objects, with one
* ValidationResult object for each field examined by the validator that
* failed validation.
*
* You must override this method in a subclass of a validator class.
*/
List<ValidationResult> doValidation(dynamic value) {
List<ValidationResult> results = super.doValidation(value);
// Return if there are errors
// or if the required property is set to [false] and length is 0.
String val = value != null? value.toString() : "";
if (results.length > 0 || ((val.length == 0) && !required))
return results;
else
return _validateNumber(value);
}
/**
* Validate [value] and return List of [ValidationResult] objects, with one
* ValidationResult object for each field examined by the validator.
*/
List<ValidationResult> _validateNumber(dynamic value) {
List<ValidationResult> results = [];
String input = value.toString();
int len = input.length;
bool isNegative = false;
int i;
String c;
// Make sure the formatting character parameters are unique,
// are not digits or the negative sign,
// and that the separators are one character.
String invalidFormChars = Validator.DECIMAL_DIGITS + "-";
if (decimalSeparator == thousandsSeparator ||
invalidFormChars.indexOf(decimalSeparator) != -1 ||
invalidFormChars.indexOf(thousandsSeparator) != -1 ||
decimalSeparator.length != 1 ||
thousandsSeparator.length != 1) {
results.add(new ValidationResult(true, invalidFormatCharsError));
return results;
}
// Check for invalid characters in input.
String validChars = Validator.DECIMAL_DIGITS + "-" + decimalSeparator + thousandsSeparator;
for (i = 0; i < len; i++) {
c = input[i];
if (validChars.indexOf(c) == -1) {
results.add(new ValidationResult(true, invalidCharError));
return results;
}
}
// Check if the input is negative.
if (input[0] == "-") {
if (len == 1) {
// we have only '-' char
results.add(new ValidationResult(true, invalidCharError));
return results;
} else if (len == 2 && input[1] == '.') {
// handle "-."
results.add(new ValidationResult(true, invalidCharError));
return results;
}
// Check if negative input is allowed.
if (!allowNegative) {
results.add(new ValidationResult(true, negativeError));
return results;
}
// Strip off the minus sign, update some variables.
input = input.substring(1);
len--;
isNegative = true;
}
// Make sure there's only one decimal point.
if (input.indexOf(decimalSeparator) != input.lastIndexOf(decimalSeparator)) {
results.add(new ValidationResult(true, decimalPointCountError));
return results;
}
// Make sure every character after the decimal is a digit,
// and that there aren't too many digits after the decimal point:
// if domain is int there should be none,
// otherwise there should be no more than specified by precision.
int decimalSeparatorIndex = input.indexOf(decimalSeparator);
if (decimalSeparatorIndex != -1) {
int numDigitsAfterDecimal = 0;
if (i == 1 && i == len) {
// we only have a '.'
results.add(new ValidationResult(true, invalidCharError));
return results;
}
for (i = decimalSeparatorIndex + 1; i < len; i++) {
// This character must be a digit.
if (Validator.DECIMAL_DIGITS.indexOf(input[i]) == -1) {
results.add(new ValidationResult(true, invalidCharError));
return results;
}
++numDigitsAfterDecimal;
// There may not be any non-zero digits after the decimal
// if domain is int.
if (domain == NumberValidator.INTEGER && input[i] != "0") {
results.add(new ValidationResult(true, integerError));
return results;
}
// Make sure precision is not exceeded.
if (precision != -1 && numDigitsAfterDecimal > precision) {
results.add(new ValidationResult(true, precisionError));
return results;
}
}
}
// Make sure the input begins with a digit or a decimal point.
if (Validator.DECIMAL_DIGITS.indexOf(input[0]) == -1 && input[0] != decimalSeparator) {
results.add(new ValidationResult(true, invalidCharError));
return results;
}
// Make sure that every character before the decimal point
// is a digit or is a thousands separator.
// If it's a thousands separator,
// make sure it's followed by three consecutive digits.
int end = decimalSeparatorIndex == -1 ? len : decimalSeparatorIndex;
for (i = 1; i < end; i++) {
c = input[i];
if (c == thousandsSeparator) {
if (c == thousandsSeparator) {
if ((end - i != 4 &&
input[i + 4] != thousandsSeparator) ||
Validator.DECIMAL_DIGITS.indexOf(input[i + 1]) == -1 ||
Validator.DECIMAL_DIGITS.indexOf(input[i + 2]) == -1 ||
Validator.DECIMAL_DIGITS.indexOf(input[i + 3]) == -1) {
results.add(new ValidationResult(true, separationError));
return results;
}
}
} else if (Validator.DECIMAL_DIGITS.indexOf(c) == -1) {
results.add(new ValidationResult(true, invalidCharError));
return results;
}
}
// Make sure the input is within the specified range.
if (minValue != null || maxValue != null) {
// First strip off the thousands separators.
for (i = 0; i < end; i++) {
if (input[i] == thousandsSeparator) {
String left = input.substring(0, i);
String right = input.substring(i + 1);
input = left + right;
}
}
// Translate the value back into standard english
// If the decimalSeperator is not '.' we need to change it to '.'
// so that the number casting will work properly
if (decimalSeparator != '.') {
int dIndex = input.indexOf(decimalSeparator);
if (dIndex != -1) {
String dLeft = input.substring(0, dIndex);
String dRight = input.substring(dIndex + 1);
input = dLeft + '.' + dRight;
}
}
// Check bounds
double x = double.parse(input, (String source) => 0.0);
if (isNegative)
x = -x;
if (minValue != null && x < minValue) {
results.add(new ValidationResult(true, lowerThanMinError));
return results;
}
if (maxValue != null && x > maxValue) {
results.add(new ValidationResult(true, exceedsMaxError));
return results;
}
}
return results;
}
}
Extends
Validator > WidgetValidator > NumberValidator
Static Properties
const String DOUBLE #
static const String DOUBLE = "double"
const String INTEGER #
static const String INTEGER = "integer"
Constructors
new NumberValidator(Widget widget, {bool allowNegative: true, String decimalPointCountError: "The decimal separator can only occur once.", String decimalSeparator: ".", String domain: NumberValidator.DOUBLE, String exceedsMaxError: "The number entered is too large.", String integerError: "The number must be an integer.", String invalidCharError: "The input contains invalid characters.", String invalidFormatCharsError: "One of the formatting parameters is invalid.", String lowerThanMinError: "The amount entered is too small.", num maxValue: null, num minValue: null, String negativeError: "The amount may not be negative.", int precision: -1, String precisionError: "The amount entered has too many digits beyond the decimal point.", String separationError: "The thousands separator must be followed by three digits.", String thousandsSeparator: ","}) #
Creates a new Object instance.
Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.
NumberValidator(Widget widget, {
this.allowNegative:true,
this.decimalPointCountError:"The decimal separator can only occur once.",
this.decimalSeparator:".",
this.domain:NumberValidator.DOUBLE,
this.exceedsMaxError:"The number entered is too large.",
this.integerError:"The number must be an integer.",
this.invalidCharError:"The input contains invalid characters.",
this.invalidFormatCharsError:"One of the formatting parameters is invalid.",
this.lowerThanMinError:"The amount entered is too small.",
this.maxValue:null,
this.minValue:null,
this.negativeError:"The amount may not be negative.",
this.precision:-1,
this.precisionError:"The amount entered has too many digits beyond the decimal point.",
this.separationError:"The thousands separator must be followed by three digits.",
this.thousandsSeparator:","}) : super(widget);
Properties
bool allowNegative #
Specifies whether negative numbers are permitted. Allowed by default.
bool allowNegative
String decimalPointCountError #
Error message when the decimal separator character occurs more than once. By default equals "The decimal separator can occur only once."
String decimalPointCountError
String decimalSeparator #
The character used to separate the whole from the fractional part of the number. Cannot be a digit and must be distinct from the thousandsSeparator. By default equals "."
String decimalSeparator
String domain #
Type of number to be validated. Permitted values are NumberValidator.INTEGER and NumberValidator.DOUBLE. By default equals NumberValidator.DOUBLE.
String domain
bool enabled #
Property to enable/disable validation process.
Setting this value to false will stop the validator from performing validation. When a validator is disabled, it dispatches no events, and the validate method returns ValidationEvent.VALID instance.
bool enabled = true
String exceedsMaxError #
Error message when the value exceeds the maxValue property. By default equals "The number entered is too large."
String exceedsMaxError
String integerError #
Error message when the number must be an integer, as defined by the domain property. By default it's equals "The number must be an integer."
String integerError
String invalidCharError #
Error message when the value contains invalid characters.
By default it equals "The input contains invalid characters."
String invalidCharError
String invalidFormatCharsError #
Error message when the value contains invalid format characters, which means that it contains a digit or minus sign (-) as a separator character, or it contains two or more consecutive separator characters.
By default it equals "One of the formatting parameters is invalid."
String invalidFormatCharsError
List<ValidationListener> listeners #
List of ValidationListener's
List<ValidationListener> listeners = new List<ValidationListener>()
String lowerThanMinError #
Error message when the value is less than minValue.
By default it equals "The amount entered is too small."
String lowerThanMinError
num maxValue #
Maximum value for a valid number. A value of null means there is no maximum.
num maxValue
num minValue #
Minimum value for a valid number. A value of null means there is no minimum.
num minValue
String negativeError #
Error message when the value is negative and the allowNegative
property is false.
By default it equals "The amount may not be negative."
String negativeError
OnInvalid onInvalid #
Callback function invokes when result of validation is invalid.
OnInvalid onInvalid
OnValid onValid #
Callback function invokes when result of validation is valid.
OnValid onValid
int precision #
The maximum number of digits allowed to follow the decimal point. Can be any nonnegative integer.
int precision
String precisionError #
Error message when the value has a precision that exceeds the value defined by the precision property.
By "default" it equals "The amount entered has too many digits beyond the decimal point."
String precisionError
bool required #
If true specifies that a missing or empty value causes a validation error.
bool required = true
String requiredError #
Error message when a value is missing and the required property is true.
By default equals "This field is required."
String requiredError = "This field is required."
String separationError #
Error message when the thousands separator is in the wrong location.
By default it equals "The thousands separator must be followed by three digits."
String separationError
String thousandsSeparator #
The character used to separate thousands in the whole part of the number. Cannot be a digit and must be distinct from the decimalSeparator.
String thousandsSeparator
Methods
List<ValidationResult> doValidation(value) #
Override of the base class doValidation() method
to validate a number.
<p>You do not call this method directly; Flex calls it as part of performing a validation. If you create a custom Validator class, you must implement this method. </p>
@param value Object to validate.
@return An Array of ValidationResult objects, with one ValidationResult object for each field examined by the validator.
@langversion 3.0 @playerversion Flash 9 @playerversion AIR 1.1 @productversion Flex 3
Executes the validation logic of this validatorto validate a number. Invalid result returns an List of ValidationResult objects, with one ValidationResult object for each field examined by the validator that failed validation.
You must override this method in a subclass of a validator class.
List<ValidationResult> doValidation(dynamic value) {
List<ValidationResult> results = super.doValidation(value);
// Return if there are errors
// or if the required property is set to [false] and length is 0.
String val = value != null? value.toString() : "";
if (results.length > 0 || ((val.length == 0) && !required))
return results;
else
return _validateNumber(value);
}
ValidationEvent validate(value, [bool fireEvent = true]) #
Performs validation of value and notifies the listeners of the result if fireEvent equals true.
ValidationEvent validate(dynamic value, [bool fireEvent = true]) {
ValidationEvent resultEvent;
if (enabled && (value != null || required)) {
// Validate if the target is required or our value is non-null.
resultEvent = _processValidation(value);
} else {
// We assume if value is null and required is false that
// validation was successful.
resultEvent = new ValidationEvent(ValidationEvent.VALID);
}
// Send notification to listeners
if (fireEvent && resultEvent != null) {
listeners.forEach((ValidationListener listener){
listener(resultEvent);
});
}
// Invoke callback validation functions
if (onValid != null && resultEvent.type == ValidationEvent.VALID) {
onValid();
} else if (onInvalid != null && resultEvent.type == ValidationEvent.INVALID) {
onInvalid(resultEvent.results);
}
return resultEvent;
}