Building Forms
This guide walks through building a complete course enrollment form step by step, covering field creation, validation, layout, sections, and conditional logic.
Step 1: Define the Form Structure
Plan the fields and their types before writing code:
| Field | Type | Validation | Width |
|---|---|---|---|
| First Name | text | required, min 2 chars | half |
| Last Name | text | required, min 2 chars | half |
| text | required, email format | half | |
| Phone | phone | required | half |
| Course | select | required | full |
| Enrollment Type | select | required | half |
| Start Date | dateTime | required, future date | half |
| Payment Method | select | required when paid | full |
| Notifications | boolean | none | full |
| Schedule | select | none | full |
Step 2: Create the Basic Form
dart
import 'package:vyuh_feature_forms/dsl/form_builder.dart';
final form = FormBuilder(title: 'Course Enrollment')
.text('first_name', title: 'First Name')
.required('First name is required')
.minLength(2)
.text('last_name', title: 'Last Name')
.required('Last name is required')
.minLength(2)
.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')
.build();At this point you have a form with 4 fields in a 2-column layout.
Step 3: Add Course Selection
dart
// ... after phone field
.select('course', title: 'Course')
.option('flutter_101', title: 'Flutter 101')
.option('dart_advanced', title: 'Advanced Dart')
.option('mobile_arch', title: 'Mobile Architecture')
.option('ui_design', title: 'UI Design Principles')
.required('Please select a course')Step 4: Add Enrollment and Date
dart
.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')Step 5: Add Conditional Payment
The payment method should only appear when enrollment type is "paid":
dart
.select('payment_method', title: 'Payment Method')
.option('credit_card', title: 'Credit Card')
.option('bank_transfer', title: 'Bank Transfer')
.option('invoice', title: 'Invoice')
.showWhen(When.fieldEquals('enrollment_type', 'paid'))
.required('Payment method is required for paid enrollment')Step 6: Group Preferences in a Section
dart
.section('Preferences', (s) => s
.boolean('notifications', title: 'Email Notifications')
.help('Receive updates about course schedule and materials')
.select('schedule', title: 'Preferred Schedule')
.option('morning', title: 'Morning (9am - 12pm)')
.option('afternoon', title: 'Afternoon (1pm - 5pm)')
.option('evening', title: 'Evening (6pm - 9pm)'),
collapsible: true,
description: 'Optional preferences for your enrollment',
)Step 7: Build and Use
dart
.build();
// Validate and submit
void submit() {
if (form.validate()) {
final values = form.currentValues;
// values = {
// 'first_name': 'Alice',
// 'last_name': 'Smith',
// 'email': 'alice@example.com',
// 'phone': '+1-555-0100',
// 'course': 'flutter_101',
// 'enrollment_type': 'paid',
// 'start_date': DateTime(...),
// 'payment_method': 'credit_card',
// 'notifications': true,
// 'schedule': 'morning',
// }
enrollStudent(values);
}
}Working with Form Values
Reading Values
dart
// All values
final all = form.currentValues;
// Single value
final email = form.getFieldValue('email') as String?;Setting Values
dart
// Single field
form.setFieldValue('enrollment_type', 'paid');
// Multiple fields
form.patchValues({
'first_name': 'Bob',
'last_name': 'Jones',
'email': 'bob@example.com',
});Listening for Changes
dart
form.addListener(() {
print('Form changed: ${form.currentValues}');
print('Valid: ${form.isValid}');
});Using MobX Observable Validity
dart
// In a Flutter widget
Observer(
builder: (_) => ElevatedButton(
onPressed: form.valid.value ? _submit : null,
child: Text('Submit'),
),
)Pre-populating for Edit Mode
dart
// Load existing enrollment
final existing = await api.getEnrollment(enrollmentId);
final form = FormBuilder(title: 'Edit Enrollment')
.text('first_name', title: 'First Name').required()
.text('email', title: 'Email').required().email()
// ... other fields
.build(initialValues: {
'first_name': existing.firstName,
'email': existing.email,
'course': existing.courseId,
'enrollment_type': existing.type,
});Disposing
Always dispose forms when done to clean up subscriptions:
dart
@override
void dispose() {
form.dispose();
super.dispose();
}Next Steps
- Field Configuration -- Detailed per-field configuration
- Validation Patterns -- Real-world validation examples
- Dynamic Behavior -- Advanced rule patterns