List Validation Examples
Learn how to validate lists and iterables with Validasi's list validation rules.
Basic List Validation
Simple List
dart
import 'package:validasi/validasi.dart';
import 'package:validasi/rules.dart';
final tagsSchema = Validasi.list<String>([
IterableRules.minLength(1, message: 'At least one tag required'),
]);
// Valid
print(tagsSchema.validate(['dart', 'flutter']).isValid); // true
// Invalid
print(tagsSchema.validate([]).isValid); // falseList with Element Validation
dart
final namesSchema = Validasi.list<String>([
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.string([
StringRules.minLength(2),
])
),
]);
// Valid
print(namesSchema.validate(['John', 'Jane', 'Bob']).isValid); // true
// Invalid - empty string
print(namesSchema.validate(['John', '', 'Bob']).isValid); // falseLength Validation
Minimum Length
dart
final minSchema = Validasi.list<int>([
IterableRules.minLength(3, message: 'List must have at least 3 items'),
]);
print(minSchema.validate([1, 2, 3]).isValid); // true
print(minSchema.validate([1, 2]).isValid); // falseCombined Length Rules
dart
final rangeSchema = Validasi.list<String>([
IterableRules.minLength(2),
IterableRules.forEach(
Validasi.string([
StringRules.minLength(1),
])
),
InlineRule<List<String>>((list) {
if (list.length > 10) {
return 'Too many items (max 10)';
}
return null;
}),
]);
// Valid
print(rangeSchema.validate(['a', 'b', 'c']).isValid); // true
// Invalid - too few
print(rangeSchema.validate(['a']).isValid); // false
// Invalid - too many
print(rangeSchema.validate(List.generate(11, (i) => 'item$i')).isValid); // falseForEach Validation
String List
dart
final emailsSchema = Validasi.list<String>([
IterableRules.forEach(
Validasi.string([
Transform((value) => value?.trim().toLowerCase()),
StringRules.minLength(5),
InlineRule<String>((value) {
return value.contains('@') ? null : 'Invalid email';
}),
])
),
]);
final result = emailsSchema.validate([
'JOHN@EXAMPLE.COM',
'JANE@EXAMPLE.COM',
]);
print(result.isValid); // true
print(result.data); // ['john@example.com', 'jane@example.com']Number List
dart
final scoresSchema = Validasi.list<int>([
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.number<int>([
NumberRules.moreThanEqual(0),
NumberRules.lessThanEqual(100),
])
),
]);
// Valid
print(scoresSchema.validate([85, 92, 78]).isValid); // true
// Invalid - out of range
print(scoresSchema.validate([85, 105, 78]).isValid); // falseNested Lists
List of Lists
dart
final matrixSchema = Validasi.list<List<int>>([
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.list<int>([
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.number<int>([
NumberRules.moreThanEqual(0),
])
),
])
),
]);
// Valid - 2D matrix
final matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
print(matrixSchema.validate(matrix).isValid); // trueList of Maps
dart
final usersSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'id': Validasi.number<int>([
NumberRules.moreThan(0),
]),
'name': Validasi.string([
StringRules.minLength(1),
]),
'email': Validasi.string([
Transform((value) => value?.trim().toLowerCase()),
]),
}),
])
),
]);
final users = [
{'id': 1, 'name': 'John', 'email': 'JOHN@EXAMPLE.COM'},
{'id': 2, 'name': 'Jane', 'email': 'JANE@EXAMPLE.COM'},
];
final result = usersSchema.validate(users);
print('Valid: ${result.isValid}');
print('First email: ${result.data[0]['email']}'); // john@example.comNullable Lists
Optional List
dart
final optionalTagsSchema = Validasi.list<String>([
Nullable(),
IterableRules.minLength(1),
IterableRules.forEach(
Validasi.string([StringRules.minLength(2)])
),
]);
// Valid
print(optionalTagsSchema.validate(null).isValid); // true
print(optionalTagsSchema.validate(['dart', 'flutter']).isValid); // true
// Invalid - empty list
print(optionalTagsSchema.validate([]).isValid); // falseList with Nullable Elements
dart
final mixedSchema = Validasi.list<String?>([
IterableRules.forEach(
Validasi.string([
Nullable(),
StringRules.minLength(2),
])
),
]);
// Valid - contains nulls
print(mixedSchema.validate(['hello', null, 'world']).isValid); // trueList Transformations
Filter Empty Strings
dart
final cleanListSchema = Validasi.list<String>([
Transform((list) {
return list?.where((item) => item.isNotEmpty).toList();
}),
IterableRules.minLength(1),
]);
final result = cleanListSchema.validate(['a', '', 'b', '', 'c']);
print(result.data); // ['a', 'b', 'c']Trim All Strings
dart
final trimmedSchema = Validasi.list<String>([
IterableRules.forEach(
Validasi.string([
Transform((value) => value?.trim()),
StringRules.minLength(1),
])
),
]);
final result = trimmedSchema.validate([' hello ', ' world ']);
print(result.data); // ['hello', 'world']Sort List
dart
final sortedSchema = Validasi.list<int>([
Transform((list) {
if (list == null) return null;
final sorted = List<int>.from(list);
sorted.sort();
return sorted;
}),
]);
final result = sortedSchema.validate([3, 1, 4, 1, 5, 9]);
print(result.data); // [1, 1, 3, 4, 5, 9]Remove Duplicates
dart
final uniqueSchema = Validasi.list<String>([
Transform((list) {
return list?.toSet().toList();
}),
IterableRules.minLength(1),
]);
final result = uniqueSchema.validate(['a', 'b', 'a', 'c', 'b']);
print(result.data); // ['a', 'b', 'c']Real-World Examples
Todo List
dart
final todoListSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.minLength(1, message: 'Add at least one task'),
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'id': Validasi.number<int>([
NumberRules.moreThan(0),
]),
'title': Validasi.string([
Transform((value) => value?.trim()),
StringRules.minLength(1, message: 'Task title required'),
StringRules.maxLength(200),
]),
'completed': Validasi.any<bool>(),
'priority': Validasi.string([
Nullable(),
StringRules.oneOf(['low', 'medium', 'high']),
]),
}),
])
),
]);
final todos = [
{
'id': 1,
'title': ' Complete documentation ',
'completed': false,
'priority': 'high',
},
{
'id': 2,
'title': 'Review pull requests',
'completed': true,
'priority': 'medium',
},
];
final result = todoListSchema.validate(todos);
print('Valid: ${result.isValid}');
print('First task: ${result.data[0]['title']}'); // 'Complete documentation'File Upload List
dart
final filesSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.minLength(1, message: 'Select at least one file'),
InlineRule<List<Map<String, dynamic>>>((list) {
if (list.length > 5) {
return 'Maximum 5 files allowed';
}
return null;
}),
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'name': Validasi.string([
StringRules.minLength(1),
]),
'size': Validasi.number<int>([
NumberRules.moreThan(0),
NumberRules.lessThanEqual(10 * 1024 * 1024), // 10MB
]),
'type': Validasi.string([
StringRules.oneOf([
'image/jpeg',
'image/png',
'image/gif',
'application/pdf',
]),
]),
}),
])
),
]);
final files = [
{
'name': 'photo.jpg',
'size': 2048576, // 2MB
'type': 'image/jpeg',
},
{
'name': 'document.pdf',
'size': 1024000, // 1MB
'type': 'application/pdf',
},
];
print(filesSchema.validate(files).isValid); // trueShopping Cart
dart
final cartSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.minLength(1, message: 'Cart is empty'),
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'product_id': Validasi.number<int>([
NumberRules.moreThan(0),
]),
'name': Validasi.string([
StringRules.minLength(1),
]),
'quantity': Validasi.number<int>([
NumberRules.moreThan(0),
NumberRules.lessThanEqual(99),
]),
'price': Validasi.number<double>([
NumberRules.moreThan(0.0),
]),
}),
])
),
InlineRule<List<Map<String, dynamic>>>((items) {
// Calculate total
final total = items.fold<double>(
0.0,
(sum, item) => sum + (item['price'] * item['quantity']),
);
if (total > 10000.0) {
return 'Order total exceeds maximum allowed';
}
return null;
}),
]);
final cart = [
{
'product_id': 1,
'name': 'Laptop',
'quantity': 1,
'price': 999.99,
},
{
'product_id': 2,
'name': 'Mouse',
'quantity': 2,
'price': 29.99,
},
];
print(cartSchema.validate(cart).isValid); // trueCoordinate List
dart
final coordinatesSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.minLength(2, message: 'At least 2 points required'),
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'lat': Validasi.number<double>([
NumberRules.moreThanEqual(-90.0),
NumberRules.lessThanEqual(90.0),
]),
'lng': Validasi.number<double>([
NumberRules.moreThanEqual(-180.0),
NumberRules.lessThanEqual(180.0),
]),
}),
])
),
]);
final route = [
{'lat': 37.7749, 'lng': -122.4194}, // San Francisco
{'lat': 34.0522, 'lng': -118.2437}, // Los Angeles
{'lat': 40.7128, 'lng': -74.0060}, // New York
];
print(coordinatesSchema.validate(route).isValid); // trueTag Cloud
dart
final tagCloudSchema = Validasi.list<String>([
Transform((list) {
// Remove duplicates and trim
return list?.map((tag) => tag.trim().toLowerCase())
.where((tag) => tag.isNotEmpty)
.toSet()
.toList();
}),
IterableRules.minLength(1, message: 'At least one tag required'),
InlineRule<List<String>>((list) {
if (list.length > 20) {
return 'Maximum 20 tags allowed';
}
return null;
}),
IterableRules.forEach(
Validasi.string([
StringRules.minLength(2),
StringRules.maxLength(50),
])
),
]);
final tags = [
' Flutter ',
'DART',
'flutter', // duplicate
'Mobile',
'dart', // duplicate
'',
'UI',
];
final result = tagCloudSchema.validate(tags);
print('Valid: ${result.isValid}');
print('Tags: ${result.data}'); // ['flutter', 'dart', 'mobile', 'ui']Custom List Validations
Unique Elements
dart
final uniqueListSchema = Validasi.list<String>([
IterableRules.minLength(1),
InlineRule<List<String>>((list) {
final unique = list.toSet();
if (unique.length != list.length) {
return 'List must contain unique elements';
}
return null;
}),
]);
// Valid
print(uniqueListSchema.validate(['a', 'b', 'c']).isValid); // true
// Invalid - duplicates
print(uniqueListSchema.validate(['a', 'b', 'a']).isValid); // falseSorted List
dart
final sortedListSchema = Validasi.list<int>([
IterableRules.minLength(2),
InlineRule<List<int>>((list) {
for (int i = 1; i < list.length; i++) {
if (list[i] < list[i - 1]) {
return 'List must be sorted in ascending order';
}
}
return null;
}),
]);
// Valid
print(sortedListSchema.validate([1, 2, 3, 4]).isValid); // true
// Invalid
print(sortedListSchema.validate([1, 3, 2, 4]).isValid); // falseMax Total Size
dart
final sizedListSchema = Validasi.list<String>([
InlineRule<List<String>>((list) {
final totalLength = list.fold<int>(0, (sum, str) => sum + str.length);
if (totalLength > 1000) {
return 'Total text length exceeds 1000 characters';
}
return null;
}),
]);No Consecutive Duplicates
dart
final noConsecutiveSchema = Validasi.list<int>([
InlineRule<List<int>>((list) {
for (int i = 1; i < list.length; i++) {
if (list[i] == list[i - 1]) {
return 'No consecutive duplicate values allowed';
}
}
return null;
}),
]);
// Valid
print(noConsecutiveSchema.validate([1, 2, 1, 3]).isValid); // true
// Invalid
print(noConsecutiveSchema.validate([1, 2, 2, 3]).isValid); // falseError Tracking in Lists
Individual Element Errors
dart
final emailListSchema = Validasi.list<String>([
IterableRules.forEach(
Validasi.string([
InlineRule<String>((value) {
return value.contains('@') ? null : 'Invalid email format';
}),
])
),
]);
final result = emailListSchema.validate([
'valid@example.com',
'invalid-email',
'another@example.com',
'also-invalid',
]);
print('Valid: ${result.isValid}'); // false
// Print errors with indices
for (var error in result.errors) {
print('[${error.path?.join('.')}] ${error.message}');
}
// Output:
// [1] Invalid email format
// [3] Invalid email formatNested List Errors
dart
final nestedSchema = Validasi.list<List<int>>([
IterableRules.forEach(
Validasi.list<int>([
IterableRules.forEach(
Validasi.number<int>([
NumberRules.moreThanEqual(0, message: 'Must be non-negative'),
])
),
])
),
]);
final result = nestedSchema.validate([
[1, 2, 3],
[4, -5, 6],
[7, 8, -9],
]);
for (var error in result.errors) {
print('[${error.path?.join('.')}] ${error.message}');
}
// Output:
// [1.1] Must be non-negative
// [2.2] Must be non-negativeList with Complex Validation
Conditional Element Validation
dart
final conditionalListSchema = Validasi.list<Map<String, dynamic>>([
IterableRules.forEach(
Validasi.map<dynamic>([
MapRules.hasFields({
'type': Validasi.string([
StringRules.oneOf(['text', 'number', 'date']),
]),
'value': Validasi.any<dynamic>([Required()]),
}),
Having((context, value) {
if (value is Map) {
final type = value['type'];
final val = value['value'];
if (type == 'number' && val is! num) {
return 'Value must be a number when type is "number"';
}
if (type == 'date' && val is! String) {
return 'Value must be a string when type is "date"';
}
}
return null;
}),
])
),
]);
final items = [
{'type': 'text', 'value': 'Hello'},
{'type': 'number', 'value': 42},
{'type': 'date', 'value': '2024-01-15'},
];
print(conditionalListSchema.validate(items).isValid); // true