Registration Form Email: ______________________ Password: ___________________ [ Register ]
Custom validators in Flutter - Mini App: Build & Ship
import 'package:flutter/material.dart'; class RegistrationForm extends StatefulWidget { @override State<RegistrationForm> createState() => _RegistrationFormState(); } class _RegistrationFormState extends State<RegistrationForm> { final _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Registration Form')), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( children: [ // TODO: Add email TextFormField with custom validator // TODO: Add password TextFormField with custom validator const SizedBox(height: 20), ElevatedButton( onPressed: () { // TODO: Validate form and show message }, child: const Text('Register'), ), ], ), ), ), ); } }
import 'package:flutter/material.dart'; class RegistrationForm extends StatefulWidget { @override State<RegistrationForm> createState() => _RegistrationFormState(); } class _RegistrationFormState extends State<RegistrationForm> { final _formKey = GlobalKey<FormState>(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); String? _emailValidator(String? value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } if (!value.contains('@') || !value.contains('.')) { return 'Enter a valid email address'; } return null; } String? _passwordValidator(String? value) { if (value == null || value.isEmpty) { return 'Please enter your password'; } if (value.length < 8) { return 'Password must be at least 8 characters'; } return null; } void _submit() { if (_formKey.currentState?.validate() ?? false) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Registration successful!')), ); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Registration Form')), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( children: [ TextFormField( controller: _emailController, decoration: const InputDecoration(labelText: 'Email'), keyboardType: TextInputType.emailAddress, validator: _emailValidator, ), TextFormField( controller: _passwordController, decoration: const InputDecoration(labelText: 'Password'), obscureText: true, validator: _passwordValidator, ), const SizedBox(height: 20), ElevatedButton( onPressed: _submit, child: const Text('Register'), ), ], ), ), ), ); } }
This solution uses two custom validator functions: _emailValidator and _passwordValidator. Each checks the input and returns an error message string if invalid or null if valid.
The email validator checks if the input contains both '@' and '.' characters to roughly validate an email format.
The password validator ensures the password is at least 8 characters long.
When the Register button is pressed, the form validates all fields. If all are valid, a success message appears using a SnackBar. Otherwise, the invalid fields show error messages below them.
This approach helps beginners understand how to create and use custom validation logic in Flutter forms.
Registration Form Email: user@example.com Password: ******** [ Register ]
Practice
Solution
Step 1: Understand validator return type
A custom validator returns a String error message if input is invalid, otherwise null.Step 2: Identify valid input return
When input is valid, the validator returns null to indicate no error.Final Answer:
null -> Option BQuick Check:
Valid input returns null [OK]
- Returning empty string instead of null
- Returning boolean true/false
- Returning error message on valid input
Solution
Step 1: Check correct Dart syntax for validator
The validator must return a String or null. validator: (value) => value!.isEmpty ? 'Enter text' : null uses a concise lambda with a ternary operator correctly.Step 2: Identify null safety and return values
validator: (value) => value!.isEmpty ? 'Enter text' : null uses value! to assert non-null and returns error string if empty, else null.Final Answer:
validator: (value) => value!.isEmpty ? 'Enter text' : null -> Option DQuick Check:
Correct syntax uses ternary and returns null on valid input [OK]
- Missing return statement in block syntax
- Using if without else in lambda
- Returning null on empty input instead of error
validator: (value) {
if (value == null || value.length < 5) {
return 'Too short';
}
return null;
}
What happens if the user enters "abc"?Solution
Step 1: Analyze input length check
The validator checks if value is null or length less than 5, then returns 'Too short'.Step 2: Apply input "abc" to condition
"abc" length is 3, which is less than 5, so validator returns 'Too short'.Final Answer:
The form shows error message 'Too short' -> Option CQuick Check:
Input length < 5 triggers error message [OK]
- Ignoring null check and assuming no error
- Confusing return null with error message
- Assuming validator crashes on short input
validator: (value) {
if (value.isEmpty) {
return 'Cannot be empty';
}
}Solution
Step 1: Check null safety on value
value is nullable String?, so calling value.isEmpty without null check causes error.Step 2: Identify missing null check
Must check if value is null before calling isEmpty to avoid runtime error.Final Answer:
Using isEmpty on nullable value without null check -> Option AQuick Check:
Always check for null before isEmpty on nullable String [OK]
- Assuming value is non-null without checking
- Not returning null for valid input (though important)
- Confusing return types of validator
Solution
Step 1: Check null and '@' presence
validator: (value) { if (value == null || !value.contains('@')) return 'Invalid email'; if (!value.endsWith('.com')) return 'Must end with .com'; return null; } first checks if value is null or missing '@', returning 'Invalid email'.Step 2: Check if ends with '.com'
Then it checks if value ends with '.com', returning specific error if not.Step 3: Return null if all checks pass
If both checks pass, it returns null indicating valid input.Final Answer:
validator: (value) { if (value == null || !value.contains('@')) return 'Invalid email'; if (!value.endsWith('.com')) return 'Must end with .com'; return null; } -> Option AQuick Check:
Separate checks with clear error messages [OK]
- Combining conditions incorrectly with && or ||
- Returning null on null input without error
- Not checking null before calling methods
Ready to prove it?
Pass the test and this pattern moves unknown
