flutter-bloc-forms
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseForm Architecture with BLoC
基于BLoC的表单架构
- Manage form state in a dedicated — NOT in widget
FormBlocsetState - Each form field maps to a property in the BLoC state
- Validate on field change (real-time) or on submit (batch) depending on UX requirements
- Emit ,
FormSubmitting,FormSuccessstates for submission flowFormError
- 在专门的中管理表单状态,不要在组件的
FormBloc中管理setState - 每个表单字段映射到BLoC状态中的一个属性
- 根据UX需求选择字段变更时实时验证或提交时批量验证
- 为提交流程触发、
FormSubmitting、FormSuccess状态FormError
Form Events
表单事件
- — update a single field in state
FieldChanged(field, value) - — trigger validation and submission
FormSubmitted - — clear all fields and errors
FormReset
- — 更新状态中的单个字段
FieldChanged(field, value) - — 触发验证和提交逻辑
FormSubmitted - — 清空所有字段和错误信息
FormReset
Form State
表单状态
- Use a single state class with all field values, field-level errors, and form status:
dart
sealed class FormStatus { initial, submitting, success, failure } - Field errors: keyed by field name —
Map<String, String?>means validnull
- 使用单个状态类存储所有字段值、字段级错误和表单状态:
dart
sealed class FormStatus { initial, submitting, success, failure } - 字段错误:以字段名为键的,值为
Map<String, String?>代表校验通过null
Validation Patterns
验证模式
- Validate in the domain layer — NOT in widgets or BLoCs
- Create pure validator functions that return (null = valid, string = error message):
String?dartString? validateEmail(String value) => value.contains('@') ? null : 'Invalid email'; - Compose validators:
String? validate(String v) => validateRequired(v) ?? validateEmail(v) - Use localized error messages via — no hardcoded validation strings
context.l10n
- 在领域层进行验证,不要在组件或BLoC中做验证
- 创建纯验证函数,返回(null = 校验通过,字符串 = 错误信息):
String?dartString? validateEmail(String value) => value.contains('@') ? null : 'Invalid email'; - 组合验证器:
String? validate(String v) => validateRequired(v) ?? validateEmail(v) - 通过使用本地化错误信息,不要硬编码验证字符串
context.l10n
Input Widgets
输入组件
- Use with
TextFormFieldfor consistent stylingInputDecoration - Always set for proper keyboard behavior (
textInputAction,next)done - Always set matching the field type (
keyboardType,emailAddress,phone)number - Use to restrict input (e.g.,
inputFormatters)FilteringTextInputFormatter.digitsOnly - Assign to every form field for test access
Key('feature_fieldName') - Use for login/signup forms (email, password, name)
AutofillHints - Wrap form fields with or
Focusfor proper tab orderFocusTraversalGroup
- 使用带的
InputDecoration保证样式统一TextFormField - 始终设置以获得正确的键盘行为(
textInputAction、next)done - 始终设置与字段类型匹配的(
keyboardType、emailAddress、phone)number - 使用限制输入内容(例如
inputFormatters)FilteringTextInputFormatter.digitsOnly - 为每个表单字段分配以便测试时访问
Key('feature_fieldName') - 登录/注册表单使用(邮箱、密码、姓名)
AutofillHints - 用或
Focus包裹表单字段以保证正确的tab切换顺序FocusTraversalGroup
Controller Lifecycle
控制器生命周期
- Declare as
TextEditingControllerinlate final— dispose ininitState()dispose() - Sync controllers to BLoC via callback or controller listener
onChanged
- 在中声明为
initState()类型的late final,在TextEditingController中销毁dispose() - 通过回调或控制器监听器将控制器与BLoC同步
onChanged
Form Submission
表单提交
- Disable submit button while to prevent double-submission
FormStatus.submitting - Show inline field errors below each field — not just a top-level error
- On success: navigate, show success feedback, and reset form if staying on same page
- On failure: show error feedback via or inline, keep form data intact
SnackBar
- 当时禁用提交按钮,防止重复提交
FormStatus.submitting - 在每个字段下方显示行内字段错误,不要只展示顶层错误
- 提交成功:跳转页面、展示成功提示,如果停留在当前页则重置表单
- 提交失败:通过或行内提示展示错误反馈,保留表单数据
SnackBar
Common Form Patterns
常见表单模式
- Search: Use transformer on search events (300-500ms delay)
debounce - Multi-step: Each step is a separate form state within one , validated independently
FormBloc - Dependent fields: Update dependent field options in handler (e.g., country → city)
on<FieldChanged>
- 搜索:在搜索事件上使用转换器(300-500ms延迟)
debounce - 多步骤:每个步骤是同一个下的独立表单状态,单独验证
FormBloc - 依赖字段:在处理器中更新依赖字段的选项(例如国家 → 城市)
on<FieldChanged>