Example done
This commit is contained in:
parent
b8a9d97a99
commit
0227b0782e
5 changed files with 134 additions and 8 deletions
|
@ -145,6 +145,7 @@ new Validator({
|
|||
'age': 'You must be an adult to see this page.'
|
||||
});
|
||||
```
|
||||
The string `{{value}}` will be replaced inside your error message automatically.
|
||||
|
||||
# autoParse
|
||||
Oftentimes, fields that we want to validate as numbers are passed as strings.
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
import 'package:matcher/matcher.dart';
|
||||
|
||||
final RegExp _asterisk = new RegExp(r'\*$');
|
||||
final RegExp _forbidden = new RegExp(r'\!$');
|
||||
final RegExp _forbidden = new RegExp(r'!$');
|
||||
final RegExp _optional = new RegExp(r'\?$');
|
||||
|
||||
/// Returns a value based the result of a computation.
|
||||
typedef DefaultValueFunction();
|
||||
|
||||
/// Generates an error message based on the given input.
|
||||
typedef String CustomErrorMessageFunction(item);
|
||||
|
||||
/// Determines if a value is valid.
|
||||
typedef bool Filter(value);
|
||||
|
||||
|
@ -33,7 +36,7 @@ Map<String, dynamic> autoParse(Map inputData, List<String> fields) {
|
|||
/// Enforces the validity of input data, according to [Matcher]s.
|
||||
class Validator extends Matcher {
|
||||
/// Pre-defined error messages for certain fields.
|
||||
final Map<String, String> customErrorMessages = {};
|
||||
final Map<String, dynamic> customErrorMessages = {};
|
||||
|
||||
/// Values that will be filled for fields if they are not present.
|
||||
final Map<String, dynamic> defaultValues = {};
|
||||
|
@ -105,7 +108,7 @@ class Validator extends Matcher {
|
|||
if (!customErrorMessages.containsKey(field))
|
||||
errors.add("'$field' is forbidden.");
|
||||
else
|
||||
errors.add(customErrorMessages[field]);
|
||||
errors.add(customError(field, input[field]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +117,7 @@ class Validator extends Matcher {
|
|||
if (!customErrorMessages.containsKey(field))
|
||||
errors.add("'$field' is required.");
|
||||
else
|
||||
errors.add(customErrorMessages[field]);
|
||||
errors.add(customError(field, 'none'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +125,7 @@ class Validator extends Matcher {
|
|||
if (key is String && rules.containsKey(key)) {
|
||||
var valid = true;
|
||||
var value = input[key];
|
||||
var description = new StringDescription("Field '$key': expected ");
|
||||
var description = new StringDescription("'$key': expected ");
|
||||
|
||||
for (Matcher matcher in rules[key]) {
|
||||
try {
|
||||
|
@ -132,24 +135,27 @@ class Validator extends Matcher {
|
|||
if (result.errors.isNotEmpty) {
|
||||
errors.addAll(result.errors);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!matcher.matches(value, {})) {
|
||||
if (!customErrorMessages.containsKey(key))
|
||||
errors.add(matcher.describe(description).toString().trim());
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
errors.add(e.toString());
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
data[key] = value;
|
||||
} else if (customErrorMessages.containsKey(key)) {
|
||||
errors.add(customErrorMessages[key]);
|
||||
errors.add(customError(key, input[key]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +171,22 @@ class Validator extends Matcher {
|
|||
ValidationResult checkParsed(Map inputData, List<String> fields) =>
|
||||
check(autoParse(inputData, fields));
|
||||
|
||||
/// Renders the given custom error.
|
||||
String customError(String key, value) {
|
||||
if (!customErrorMessages.containsKey(key))
|
||||
throw new ArgumentError("No custom error message registered for '$key'.");
|
||||
|
||||
var msg = customErrorMessages[key];
|
||||
|
||||
if (msg is String)
|
||||
return msg.replaceAll('{{value}}', value);
|
||||
else if (msg is CustomErrorMessageFunction) {
|
||||
return msg(value);
|
||||
}
|
||||
|
||||
throw new ArgumentError("Invalid custom error message '$key': $msg");
|
||||
}
|
||||
|
||||
/// Validates input data, and throws an error if it is invalid.
|
||||
///
|
||||
/// Otherwise, the filtered data is returned.
|
||||
|
@ -188,7 +210,7 @@ class Validator extends Matcher {
|
|||
/// Creates a copy with additional validation rules.
|
||||
Validator extend(Map<String, dynamic> schema,
|
||||
{Map<String, dynamic> defaultValues: const {},
|
||||
Map<String, String> customErrorMessages: const {},
|
||||
Map<String, dynamic> customErrorMessages: const {},
|
||||
bool overwrite: false}) {
|
||||
Map<String, dynamic> _schema = {};
|
||||
var child = new Validator.empty()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: angel_validate
|
||||
description: Cross-platform validation library based on `matcher`.
|
||||
version: 0.0.1
|
||||
version: 0.0.2
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/validate
|
||||
environment:
|
||||
|
@ -11,4 +11,5 @@ dependencies:
|
|||
dev_dependencies:
|
||||
angel_diagnostics: ^1.0.0-dev
|
||||
angel_test: ^1.0.0-dev
|
||||
browser: ^0.10.0
|
||||
test: ^0.12.18
|
37
web/index.html
Normal file
37
web/index.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>angel_validate</title>
|
||||
<meta name="viewport"
|
||||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<style>
|
||||
#errors li {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#errors li.success {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Passport Registration</h1>
|
||||
<i>Validation Example</i>
|
||||
<ul id="errors"></ul>
|
||||
<form id="form">
|
||||
<input placeholder="First Name*" name="firstName" type="text">
|
||||
<input placeholder="Last Name*" name="lastName" type="text">
|
||||
<br><br>
|
||||
<input placeholder="Age*" name="age" type="number">
|
||||
<br><br>
|
||||
<input placeholder="Family Size" name="familySize" type="number">
|
||||
<br><br>
|
||||
<input placeholder="LEAVE THIS BLANK" name="blank">
|
||||
<br><br>
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
<script src="main.dart" type="application/dart"></script>
|
||||
<script src="packages/browser/dart.js"></script>
|
||||
</body>
|
||||
</html>
|
65
web/main.dart
Normal file
65
web/main.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
import 'dart:html';
|
||||
import 'package:angel_validate/angel_validate.dart';
|
||||
|
||||
final UListElement $errors = querySelector('#errors');
|
||||
final FormElement $form = querySelector('#form');
|
||||
final InputElement $blank = querySelector('[name="blank"]');
|
||||
|
||||
final Validator formSchema = new Validator({
|
||||
'firstName*': [isString, isNotEmpty],
|
||||
'lastName*': [isString, isNotEmpty],
|
||||
'age*': [isInt, greaterThanOrEqualTo(18)],
|
||||
'familySize': [isInt, greaterThanOrEqualTo(1)],
|
||||
'blank!': []
|
||||
}, defaultValues: {
|
||||
'familySize': 1
|
||||
}, customErrorMessages: {
|
||||
'age': (age) {
|
||||
if (age is int && age < 18)
|
||||
return 'Only adults can register for passports. Sorry, kid!';
|
||||
else if (age == null || (age is String && age.trim().isEmpty))
|
||||
return 'Age is required.';
|
||||
else
|
||||
return 'Age must be a positive integer. Unless you are a monster...';
|
||||
},
|
||||
'blank':
|
||||
"I told you to leave that field blank, but instead you typed '{{value}}'..."
|
||||
});
|
||||
|
||||
main() {
|
||||
$form.onSubmit.listen((e) {
|
||||
e.preventDefault();
|
||||
$errors.children.clear();
|
||||
|
||||
var formData = {};
|
||||
|
||||
['firstName', 'lastName', 'age', 'familySize'].forEach((key) {
|
||||
formData[key] = (querySelector('[name="$key"]') as InputElement).value;
|
||||
});
|
||||
|
||||
if ($blank.value.isNotEmpty) formData['blank'] = $blank.value;
|
||||
|
||||
print('Form data: $formData');
|
||||
|
||||
try {
|
||||
var passportInfo =
|
||||
formSchema.enforceParsed(formData, ['age', 'familySize']);
|
||||
|
||||
$errors.children
|
||||
..add(success('Successfully registered for a passport.'))
|
||||
..add(success('First Name: ${passportInfo["firstName"]}'))
|
||||
..add(success('Last Name: ${passportInfo["lastName"]}'))
|
||||
..add(success('Age: ${passportInfo["age"]} years old'))
|
||||
..add(success(
|
||||
'Number of People in Family: ${passportInfo["familySize"]}'));
|
||||
} on ValidationException catch (e) {
|
||||
$errors.children.addAll(e.errors.map((error) {
|
||||
return new LIElement()..text = error;
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
LIElement success(String str) => new LIElement()
|
||||
..classes.add('success')
|
||||
..text = str;
|
Loading…
Reference in a new issue