Example done

This commit is contained in:
thosakwe 2016-12-27 11:43:27 -05:00
parent b8a9d97a99
commit 0227b0782e
5 changed files with 134 additions and 8 deletions

View file

@ -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.

View file

@ -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()

View file

@ -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
View 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
View 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;