Enrollment Form
A complete course enrollment form demonstrating field types, validation, conditional logic, sections, and layout.
Requirements
- Student name, email, phone (required)
- Course selection from predefined list
- Enrollment type: open (free) or paid
- Payment method appears only for paid enrollment
- Start date with future date constraint
- Preferences section (collapsible)
- Explicit row layout for side-by-side fields
Complete Implementation
dart
import 'package:vyuh_feature_forms/dsl/form_builder.dart';
Form buildEnrollmentForm({Map<String, dynamic>? initialValues}) {
return FormBuilder(title: 'Course Enrollment')
.description('Enroll in a course at the LMS')
// ── Student Information ───────────────────────────────
.section('Student Information', (s) => s
.text('first_name', title: 'First Name')
.required('First name is required')
.minLength(2, message: 'At least 2 characters')
.text('last_name', title: 'Last Name')
.required('Last name is required')
.minLength(2, message: 'At least 2 characters')
.text('email', title: 'Email Address')
.required('Email is required')
.email('Please enter a valid email')
.phone('phone', title: 'Phone Number')
.required('Phone number is required')
,
description: 'Your contact details',
)
// ── Course Selection ──────────────────────────────────
.section('Course Details', (s) => s
.select('course_id', title: 'Course')
.option('FLUTTER101', title: 'Flutter Fundamentals')
.option('DART201', title: 'Advanced Dart')
.option('MOBILE301', title: 'Mobile Architecture')
.option('UIDESIGN', title: 'UI Design Principles')
.option('TESTING', title: 'Testing & Quality')
.required('Please select a course')
.select('enrollment_type', title: 'Enrollment Type')
.option('open', title: 'Open Enrollment (Free)')
.option('paid', title: 'Paid Enrollment')
.required('Please select enrollment type')
.dateTime('start_date', title: 'Preferred Start Date')
.dateOnly()
.required('Start date is required')
,
)
// ── Payment (conditional) ────────────────────────────
.section('Payment Information', (s) => s
.select('payment_method', title: 'Payment Method')
.option('credit_card', title: 'Credit Card')
.option('bank_transfer', title: 'Bank Transfer')
.option('invoice', title: 'Invoice')
.required('Payment method is required')
.text('billing_email', title: 'Billing Email')
.email()
.placeholder('Leave blank to use student email')
.text('card_number', title: 'Card Number')
.showWhen(When.fieldEquals('payment_method', 'credit_card'))
.required('Card number is required')
.pattern(r'^\d{16}$', message: 'Enter 16 digits')
.text('card_expiry', title: 'Expiry (MM/YY)')
.showWhen(When.fieldEquals('payment_method', 'credit_card'))
.required()
.pattern(r'^\d{2}/\d{2}$', message: 'Format: MM/YY')
.text('card_cvv', title: 'CVV')
.showWhen(When.fieldEquals('payment_method', 'credit_card'))
.required()
.secure()
.pattern(r'^\d{3,4}$', message: '3 or 4 digits')
.text('bank_name', title: 'Bank Name')
.showWhen(When.fieldEquals('payment_method', 'bank_transfer'))
.required()
.text('account_number', title: 'Account Number')
.showWhen(When.fieldEquals('payment_method', 'bank_transfer'))
.required()
.text('company_name', title: 'Company Name')
.showWhen(When.fieldEquals('payment_method', 'invoice'))
.required()
.text('purchase_order', title: 'PO Number')
.showWhen(When.fieldEquals('payment_method', 'invoice'))
,
rules: [When.fieldEquals('enrollment_type', 'paid').show()],
)
// ── Preferences (collapsible) ────────────────────────
.section('Preferences', (s) => s
.boolean('email_notifications', title: 'Email Notifications')
.help('Receive course updates and schedule changes')
.boolean('sms_notifications', title: 'SMS Notifications')
.help('Receive text message reminders')
.select('schedule_preference', title: 'Schedule Preference')
.option('morning', title: 'Morning (9am - 12pm)')
.option('afternoon', title: 'Afternoon (1pm - 5pm)')
.option('evening', title: 'Evening (6pm - 9pm)')
.option('weekend', title: 'Weekend')
.text('special_requirements', title: 'Special Requirements')
.multiline(3)
.placeholder('Dietary needs, accessibility, etc.'),
collapsible: true,
description: 'Optional preferences for your enrollment',
)
// ── Terms ────────────────────────────────────────────
.boolean('accept_terms', title: 'I accept the terms and conditions')
.required('You must accept the terms')
.build(initialValues: initialValues);
}Usage
Creating a New Enrollment
dart
class EnrollmentPage extends StatefulWidget {
@override
State<EnrollmentPage> createState() => _EnrollmentPageState();
}
class _EnrollmentPageState extends State<EnrollmentPage> {
late final Form form;
@override
void initState() {
super.initState();
form = buildEnrollmentForm();
}
@override
void dispose() {
form.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Course Enrollment')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
vyuh.content.buildContent(context, form),
SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.end,
spacing: 12,
children: [
OutlinedButton(
onPressed: () => form.resetForm(),
child: Text('Reset'),
),
ElevatedButton(
onPressed: _submit,
child: Text('Enroll'),
),
],
),
],
),
),
);
}
Future<void> _submit() async {
if (!form.validate()) return;
// Check soft validation breaches
final breaches = form.collectSoftBreaches();
if (breaches.isNotEmpty) {
final proceed = await _confirmBreaches(breaches);
if (!proceed) return;
}
// Run async validations
final asyncValid = await form.validateAllAsync();
if (!asyncValid) return;
// Submit
final values = form.currentValues;
await api.createEnrollment(values);
}
}Editing an Existing Enrollment
dart
final existingEnrollment = await api.getEnrollment(id);
form = buildEnrollmentForm(initialValues: {
'first_name': existingEnrollment.firstName,
'last_name': existingEnrollment.lastName,
'email': existingEnrollment.email,
'phone': existingEnrollment.phone,
'course_id': existingEnrollment.courseId,
'enrollment_type': existingEnrollment.type,
'start_date': existingEnrollment.startDate,
'payment_method': existingEnrollment.paymentMethod,
});What This Demonstrates
| Feature | Usage |
|---|---|
| Sections | 4 logical groups with titles and descriptions |
| Collapsible section | Preferences section |
| Conditional section | Payment visible for paid enrollment |
| Conditional fields | Card/bank/invoice fields per payment method |
| Compound conditions | Nested visibility within conditional section |
| Validation | Required, email, pattern, min length |
| Row layout | Side-by-side fields through row blocks and row item spans |
| Secure field | CVV field |
| Initial values | Pre-population for edit mode |
| Soft validation | Breach collection before submit |
| Async validation | Server-side checks before submit |
Next Steps
- Evaluation Survey -- Slider-based survey form
- Certification Application -- Multi-step StepForm
- Building Forms -- Step-by-step guide