form_engine 0.1.0
form_engine: ^0.1.0 copied to clipboard
Headless, controller-free, declarative form engine for Flutter and Dart.
import 'package:flutter/material.dart';
import 'package:form_engine/form_engine.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: RegistrationFormPage(),
);
}
}
class RegistrationFormPage extends StatefulWidget {
const RegistrationFormPage({super.key});
@override
State<RegistrationFormPage> createState() => _RegistrationFormPageState();
}
class _RegistrationFormPageState extends State<RegistrationFormPage> {
late final FormEngine form;
@override
void initState() {
super.initState();
form = FormEngine(
schema: FormSchema(
fields: {
'fullName': FieldSchema<String>.withValidators(
validators: Validators()
.required()
.alphaSpace()
.minLength(3)
.maxLength(50),
),
'username': FieldSchema<String>.withValidators(
validators: Validators()
.required()
.alpha()
.minLength(3)
.maxLength(20),
),
'email': FieldSchema<String>.withValidators(
validators: Validators().required().email(),
),
'phone': FieldSchema<String>.withValidators(
validators: Validators()
.required()
.numeric()
.minLength(10)
.maxLength(10),
),
'password': FieldSchema<String>.withValidators(
validators: Validators()
.required()
.minLength(8)
.maxLength(32)
.regex(
RegExp(r'^(?=.*[A-Z])(?=.*\d).*$'),
message:
'Password must contain at least one uppercase letter and one number',
),
),
'website': FieldSchema<String>.withValidators(
validators: Validators().url(),
),
},
),
);
}
void _submit() {
final isValid = form.validateAll();
setState(() {});
if (isValid) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Registration successful:\n${form.state.values}'),
),
);
}
}
@override
Widget build(BuildContext context) {
final errors = form.state.errors;
return Scaffold(
appBar: AppBar(title: const Text('Registration')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_field(
label: 'Full Name',
error: errors['fullName'],
onChanged: (v) => _update('fullName', v),
),
_field(
label: 'Username',
error: errors['username'],
onChanged: (v) => _update('username', v),
),
_field(
label: 'Email',
error: errors['email'],
onChanged: (v) => _update('email', v),
),
_field(
label: 'Phone Number',
keyboardType: TextInputType.phone,
error: errors['phone'],
onChanged: (v) => _update('phone', v),
),
_field(
label: 'Password',
obscureText: true,
error: errors['password'],
onChanged: (v) => _update('password', v),
),
_field(
label: 'Website (optional)',
error: errors['website'],
onChanged: (v) => _update('website', v),
),
const SizedBox(height: 24),
ElevatedButton(onPressed: _submit, child: const Text('Register')),
],
),
),
);
}
void _update(String field, String value) {
setState(() {
form.updateValue(field, value);
});
}
Widget _field({
required String label,
required String? error,
required ValueChanged<String> onChanged,
TextInputType? keyboardType,
bool obscureText = false,
}) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: TextField(
keyboardType: keyboardType,
obscureText: obscureText,
onChanged: onChanged,
decoration: InputDecoration(
labelText: label,
errorText: error,
border: const OutlineInputBorder(),
),
),
);
}
}