Flutter表单生成与管理插件reactive_forms_generator的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter表单生成与管理插件reactive_forms_generator的使用

reactive_forms_generator 是一个用于 reactive_forms 的代码生成器,能够帮助开发者节省大量时间并使表单类型安全。本文将详细介绍如何安装和使用该插件,并提供完整的示例代码。

动机

在传统的 reactive_forms 中,表单字段通常通过字符串标识符定义,这会导致静态类型检查的问题。此外,输出通常是 Map<String, Object>,对于强类型语言来说不太友好。reactive_forms_generator 解决了这些问题,通过代码生成的方式自动生成表单模型和相关代码。

如何使用

最低要求

  • Dart SDK: >=2.12.0 <3.0.0
  • Flutter: >= 2.2.0

安装

首先需要在 pubspec.yaml 文件中添加必要的依赖:

dependencies:
  reactive_forms:
  reactive_forms_annotations:

dev_dependencies:
  build_runner:
  reactive_forms_generator:

这会安装以下三个包:

忽略生成文件的 lint 警告

生成的代码可能会导致 linter 报警。可以通过修改 analysis_options.yaml 来忽略这些警告:

analyzer:
  exclude:
    - "**/*.gform.dart"

运行生成器

确保在运行生成器之前导入必要的包,并在文件顶部添加 part 关键字:

import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'package:reactive_forms_annotations/reactive_forms_annotations.dart';

part 'my_file.gform.dart';

然后根据你的项目是否依赖 Flutter,选择以下命令之一来运行生成器:

  • 如果项目依赖 Flutter:
    flutter pub run build_runner build
    
  • 如果项目不依赖 Flutter:
    dart pub run build_runner build
    

特性

基础示例

模型

首先定义一个简单的登录表单模型:

class Basic {
  final String email;
  final String password;

  Basic({this.email = '', this.password = ''});
}

注解

接下来为模型添加注解,以便生成器可以生成相应的表单代码:

import 'package:reactive_forms_annotations/reactive_forms_annotations.dart';

@Rf()
class Basic {
  final String email;
  final String password;

  Basic({
    @RfControl() this.email = '',
    @RfControl() this.password = '',
  });
}

验证

为表单字段添加验证规则:

import 'package:example/helpers.dart';
import 'package:reactive_forms_annotations/reactive_forms_annotations.dart';

@Rf()
class Basic {
  final String email;
  final String password;

  Basic({
    @RfControl(
      validators: const [RequiredValidator()],
    ) this.email = '',
    @RfControl(
      validators: const [RequiredValidator()],
    ) this.password = '',
  });
}

表单

基于生成的代码构建表单:

final form = BasicFormBuilder(
  model: Basic(),
  builder: (context, formModel, child) {
    return Column(
      children: [
        ReactiveTextField<String>(
          formControl: formModel.emailControl,
          validationMessages: {
            ValidationMessage.required: (_) => 'The email must not be empty',
          },
          decoration: const InputDecoration(labelText: 'Email'),
        ),
        const SizedBox(height: 8.0),
        ReactiveTextField<String>(
          formControl: formModel.passwordControl,
          obscureText: true,
          validationMessages: {
            ValidationMessage.required: (_) => 'The password must not be empty',
          },
          textInputAction: TextInputAction.done,
          decoration: const InputDecoration(labelText: 'Password'),
        ),
        const SizedBox(height: 8.0),
        ReactiveBasicFormConsumer(
          builder: (context, form, child) {
            return ElevatedButton(
              child: Text('Submit'),
              onPressed: form.form.valid
                  ? () {
                      print(form.model.email);
                      print(form.model.password);
                    }
                  : null,
            );
          },
        ),
      ],
    );
  },
);

动态表单与 FormArray

模型

定义一个邮件列表模型:

class MailingList {
  final List<String?> emailList;

  MailingList({
    this.emailList = const [],
  });
}

注解

为模型添加注解:

import 'package:example/helpers.dart';
import 'package:reactive_forms_annotations/reactive_forms_annotations.dart';

@Rf()
class MailingList {
  final List<String?> emailList;

  MailingList({
    @RfArray(
      validators: const [
        MailingListValidator(),
      ],
    ) this.emailList = const [],
  });
}

验证

定义自定义验证器:

class MailingListValidator extends Validator<dynamic> {
  const MailingListValidator() : super();

  @override
  Map<String, dynamic>? validate(AbstractControl control) {
    final formArray = control as FormArray<String>;
    final emails = formArray.value ?? [];
    final test = <String>{};

    final result = emails.fold<bool>(true,
            (previousValue, element) => previousValue && test.add(element ?? ''));

    return result ? null : <String, dynamic>{'emailDuplicates': true};
  }
}

表单

基于生成的代码构建动态表单:

final form = MailingListFormBuilder(
  model: MailingList(),
  builder: (context, formModel, child) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Expanded(
              child: ReactiveFormArray<String>(
                formArray: formModel.emailListControl,
                builder: (context, formArray, child) =>
                    Column(
                      children: formModel.emailListValue
                          .asMap()
                          .map((i, email) {
                        return MapEntry(
                            i,
                            ReactiveTextField<String>(
                              formControlName: i.toString(),
                              validationMessages: {
                                'email': (_) => 'Invalid email',
                              },
                              decoration: InputDecoration(
                                  labelText: 'Email ${i}'),
                            ));
                      })
                          .values
                          .toList(),
                    ),
              ),
            ),
            SizedBox(width: 16),
            ElevatedButton(
              onPressed: () {
                formModel.addEmailListItem('');
              },
              child: const Text('add'),
            )
          ],
        ),
        SizedBox(height: 16),
        ReactiveMailingListFormConsumer(
          builder: (context, form, child) {
            final errorText = {
              'emailDuplicates': 'Two identical emails are in the list',
            };
            final errors = <String, dynamic>{};

            form.emailListControl.errors.forEach((key, value) {
              final intKey = int.tryParse(key);
              if (intKey == null) {
                errors[key] = value;
              }
            });

            if (form.emailListControl.hasErrors && errors.isNotEmpty) {
              return Text(errorText[errors.entries.first.key] ?? '');
            } else {
              return Container();
            }
          },
        ),
        SizedBox(height: 16),
        Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: () {
                if (formModel.form.valid) {
                  print(formModel.model);
                } else {
                  formModel.form.markAllAsTouched();
                }
              },
              child: const Text('Sign Up'),
            ),
            ReactiveMailingListFormConsumer(
              builder: (context, form, child) {
                return ElevatedButton(
                  child: Text('Submit'),
                  onPressed: form.form.valid ? () {} : null,
                );
              },
            ),
          ],
        )
      ],
    );
  },
);

完整示例

以下是一个完整的示例,展示了如何在 Flutter 应用中使用 reactive_forms_generator

import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'package:reactive_forms_annotations/reactive_forms_annotations.dart';

part 'basic_form.gform.dart';

@Rf()
class Basic {
  final String email;
  final String password;

  Basic({
    @RfControl(
      validators: const [RequiredValidator(), EmailValidator()],
    ) this.email = '',
    @RfControl(
      validators: const [RequiredValidator(), MinLengthValidator(8)],
    ) this.password = '',
  });
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: LoginFormWidget(),
    );
  }
}

class LoginFormWidget extends StatelessWidget {
  final form = BasicFormBuilder(
    model: Basic(),
    builder: (context, formModel, child) {
      return Column(
        children: [
          ReactiveTextField<String>(
            formControl: formModel.emailControl,
            validationMessages: {
              ValidationMessage.required: (_) => 'The email must not be empty',
              ValidationMessage.email: (_) => 'Invalid email format',
            },
            decoration: const InputDecoration(labelText: 'Email'),
          ),
          const SizedBox(height: 8.0),
          ReactiveTextField<String>(
            formControl: formModel.passwordControl,
            obscureText: true,
            validationMessages: {
              ValidationMessage.required: (_) => 'The password must not be empty',
              ValidationMessage.minLength: (_) => 'Minimum length is 8 characters',
            },
            textInputAction: TextInputAction.done,
            decoration: const InputDecoration(labelText: 'Password'),
          ),
          const SizedBox(height: 8.0),
          ReactiveBasicFormConsumer(
            builder: (context, form, child) {
              return ElevatedButton(
                child: Text('Submit'),
                onPressed: form.form.valid
                    ? () {
                        print(form.model.email);
                        print(form.model.password);
                      }
                    : null,
              );
            },
          ),
        ],
      );
    },
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Login Form'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: form,
      ),
    );
  }
}

通过上述步骤和示例代码,你可以轻松地使用 reactive_forms_generator 插件来生成和管理 Flutter 表单。希望本文对你有所帮助!


更多关于Flutter表单生成与管理插件reactive_forms_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表单生成与管理插件reactive_forms_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,reactive_forms_generator 是一个强大的 Flutter 插件,用于动态生成和管理表单。它通过代码生成简化了表单处理流程,提高了开发效率。以下是一个基本的示例,展示如何使用 reactive_forms_generator 来创建和管理表单。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 reactive_formsreactive_forms_generator 依赖:

dependencies:
  flutter:
    sdk: flutter
  reactive_forms: ^x.y.z  # 请使用最新版本号
  reactive_forms_generator: ^x.y.z  # 请使用最新版本号
  build_runner: ^x.y.z  # 确保安装了 build_runner 以支持代码生成

2. 创建表单模型

定义一个表单模型类,并使用注解来标记字段和验证规则。例如,创建一个 UserForm 类:

import 'package:reactive_forms/reactive_forms.dart';
import 'package:reactive_forms_generator/reactive_forms_generator.dart';

part 'user_form.g.dart'; // 这是代码生成文件

@reactiveFormClass
class UserForm {
  @requiredField()
  @minLength(3)
  @maxLength(30)
  String? name;

  @requiredField()
  @email()
  String? email;

  @requiredField()
  @minLength(6)
  String? password;

  UserForm() : super();

  factory UserForm.fromJson(Map<String, dynamic> json) =>
      _$UserFormFromJson(json);

  Map<String, dynamic> toJson() => _$UserFormToJson(this);
}

// 运行以下命令生成代码:
// flutter pub run build_runner build

3. 生成代码

在终端中运行以下命令来生成代码:

flutter pub run build_runner build

4. 创建表单控件

在你的 Flutter 组件中,使用生成的表单控件来创建和管理表单。例如:

import 'package:flutter/material.dart';
import 'package:reactive_forms/reactive_forms.dart';
import 'user_form.dart'; // 导入生成的表单类

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Reactive Forms Example'),
        ),
        body: ReactiveForm(
          formGroup: FormGroup.fromGroup(UserForm.initial()),
          builder: (formGroup) {
            return Padding(
              padding: const EdgeInsets.all(16.0),
              child: Column(
                children: [
                  ReactiveTextField<String>(
                    formControlName: 'name',
                    decoration: InputDecoration(labelText: 'Name'),
                  ),
                  ReactiveTextField<String>(
                    formControlName: 'email',
                    decoration: InputDecoration(labelText: 'Email'),
                  ),
                  ReactiveTextField<String>(
                    formControlName: 'password',
                    decoration: InputDecoration(labelText: 'Password'),
                    obscureText: true,
                  ),
                  ReactiveFormErrors(formGroup: formGroup),
                  ElevatedButton(
                    onPressed: () {
                      if (formGroup.valid) {
                        // 处理有效表单数据
                        print(formGroup.value);
                      }
                    },
                    child: Text('Submit'),
                  ),
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

5. 运行应用

现在,你可以运行你的 Flutter 应用,并看到一个带有动态生成的表单控件的页面。这些控件会根据你定义的验证规则进行验证,并在表单提交时显示错误信息(如果有的话)。

这个示例展示了如何使用 reactive_forms_generator 来动态生成和管理 Flutter 表单。通过代码生成,你可以显著减少手动编写表单控件和验证逻辑的工作量。

回到顶部