带有嵌套/反应模型/reactive_forms 的颤振形式

时间:2020-12-23 14:12:41

标签: flutter flutter-web

通过不同的教程和资源,我试图在 Flutter 应用程序中获得动态表单,但我的用例看起来很高级,但我感觉很糟糕。

我的工作: 创建一个只有固定字符串和整数的反应形式。 我的表格供参考:

final form = fb.group({
    'name': ['',  Validators.required,],
    'category': ['',  Validators.required,],
    'instructions': ['',],
    'unit':  [0,  Validators.required,],
});

和:

@override
Widget build(BuildContext context) {
...
ReactiveForm(
  formGroup: this.form,
  child: Column(
  children: <Widget>[
    ReactiveTextField(
      formControlName: 'name',
      validationMessages: (control) => {
        ValidationMessage.required:
          'The name must not be empty',
      },
      ...
    ),
  ],
),

我试图实现但没有成功的目标: 嵌入另一个对象。目标是允许用户根据需要动态添加步骤。所以我采用了 Array< Step > 方式,但即使使用简单的字符串列表,我也不知道如何让它工作...... 它应该适用于:

final form = fb.group({
  ...
  'steps': fb.array([
    'step 1',
    'step 2',
  ]),
});

然后在表单中添加一个新步骤:

void _addStep(){
  final array = form.control('steps') as FormArray<String>;
  array.add(
  FormControl<String>(value: 'next step'),
  );
}

问题是,我不知道如何为此创建小部件,而且我找不到包含数组的示例。

我想我应该将 ReactiveFormArray() 添加到我的构建函数中,但我不知道如何构建应该是带有 ReactiveTextField 动态列表的单个小部件的东西(或者只是 TextFormField ,无论如何):

ReactiveFormArray(
  formArrayName: 'steps',
  builder: (BuildContext context, FormArray<dynamic> array, Widget child) {
      **??**
  },
),

我尝试了很多方法并使用reactive_forms 获得了最好的结果,遵循https://pub.dev/packages/reactive_forms,但如果您有更好的解决方案,我很乐意。

希望有人能帮助我。

1 个答案:

答案 0 :(得分:0)

使用 FormGroup 代替 fb.group 并将 [] 转换为 FormControl。

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

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

class Example extends StatefulWidget {
  @override
  _ExampleState createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  final steps = [
    'step1',
    'step2',
  ];

  final form = FormGroup({
    // 'name': FormControl<String>(validators: [Validators.required,]),
    // 'category': FormControl<String>(validators: [Validators.required,]),
    // 'instructions': FormControl<String>(),
    // 'unit': FormControl<int>(validators: [Validators.required,]),
    'steps': FormArray<String>([]),
  });

  FormArray<String> get selectedSteps => form.control('steps') as FormArray;

  @override
  void initState() {
    selectedSteps.addAll(
      steps.map((step) => FormControl<String>(value: '')).toList(),
    );
    super.initState();
  }

  Widget _buildStepListItem(step) {
    return ReactiveTextField(
      formControlName: this.steps.indexOf(step).toString(),
      decoration: InputDecoration(
        labelText: step,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Steps',
      home: Scaffold(
        body: ReactiveForm(
          formGroup: this.form,
          child: Column(
            children: [
              ReactiveFormArray<String>(
                formArrayName: 'steps',
                builder: (context, formArray, child) => Column(
                  children: this.steps.map(_buildStepListItem).toList(),
                ),
              ),
              ReactiveFormConsumer(
                builder: (context, form, child) {
                  return RaisedButton(
                    child: Text('Send'),
                    onPressed: form.valid
                        ? () {
                      print(this.selectedSteps.rawValue);
                    }
                        : null,
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}