2 种形式的 Flutter 条件渲染 - 将形式值复制到另一种形式

Flutter conditional rendering of 2 forms - duplicates the form values to the other form

我正在尝试使用 flutter reactive_forms 对两种形式进行条件渲染。但是,当我输入一种形式,然后单击一个按钮,该按钮在完全相同的位置呈现另一种形式时,相同的值也会保留在另一种形式中。唯一改变的是表单控件标签。这些表格只是彼此的副本。我已经尝试了很多方法来使值不重复,但无济于事。很长一段时间以来最糟糕的编程经历之一。

这是我的 FormGroup,我最初将其用于两种形式,因为我确实希望大部分字段重复,只是不是所有字段,例如“groceryStore”和“restaurant”,都是两种形式之间不共享。我什至尝试为每个字段名称使用单独的 FormGroup...我认为这最初是重复的原因但是当更改为两个单独的 FormGroup 时名字它没有帮助。就像它与其他条件表单字段在页面上的同一位置一样,因此它只会保留其值。当我离开页面并 return 时,我首先查看的表单具有正确的不同值。我的代码:

  FormGroup form = FormGroup({
    VeganItemFieldNames.name:
        FormControl<String>(validators: [Validators.required]),
    VeganItemFieldNames.brand:
        FormControl<String>(validators: [Validators.required]),
    VeganItemFieldNames.description:
        FormControl<String>(validators: [Validators.required]),
    VeganItemFieldNames.price:
        FormControl<double>(validators: [Validators.required]),
    VeganItemFieldNames.groceryStore:
        FormControl<String>(validators: [Validators.required]),
    VeganItemFieldNames.restaurant:
        FormControl<String>(validators: [Validators.required]),
    // VeganItemFieldNames.groceryItemCategories: FormControl<String>(),
    // VeganItemFieldNames.menuItemCategories: FormControl<String>(),
    VeganItemFieldNames.image:
        FormControl<String>(validators: [Validators.required]),
  });

我的看法:

child: ReactiveForm(
                      formGroup: viewModelState.form,
                      child: Column(
                          mainAxisSize: MainAxisSize.min,
                          crossAxisAlignment: CrossAxisAlignment.center,
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Expanded(
                                flex: 7,
                                child: KeyboardAvoider(
                                    autoScroll: true,
                                    child: Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.center,
                                        mainAxisAlignment:
                                            MainAxisAlignment.start,
                                        children: [
                                          if (viewModel.addVeganItemStrategy !=
                                              null)
                                            ...viewModel.buildFields(context)
                                        ]))),
                            Container(
                                padding: const EdgeInsets.fromLTRB(
                                    PAD_0, PAD_1, PAD_0, PAD_3),
                                child: Center(
                                    child: VpSubmitButton(
                                        text: 'Submit', onPressed: () {})))
                          ]))

视图模型:

  List<Widget> buildFields(BuildContext context1) {
    return addVeganItemStrategy.buildFields(
        context: context, form: viewModelState.form);
  }

一个策略 buildFields()

class AddGroceryItemStrategy implements AddVeganItemStrategy {
  List<Widget> buildFields({BuildContext context, FormGroup form}) {
    return [
      nameTextField(context: context, form: form),
      brandTextField(context: context),
      groceryStoreTextField(context: context),
      descriptionTextField(context: context),
      priceTextField(context: context),
      //   groceryItemCategoriesTextField(context: context, form: form),
      imageTextField(context: context),
    ];
  }

  Widget nameTextField(
      {BuildContext context, FormGroup form, String nextField}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_4, PAD_3_HALF, PAD_4),
        child: VpTextField(
            context: context,
            labelText: 'Name',
            maxLength: 40,
            formControlName: GroceryItemFieldNames.name,
            hintText: 'Name...',
            form: form,
            textInputAction: TextInputAction.next,
            nextField: nextField,
            validationMessages: (control) => {
                  'required': 'Please enter the Product Name',
                }));
  }

  Widget brandTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Brand',
          maxLength: 30,
          formControlName: GroceryItemFieldNames.brand,
          hintText: 'Brand...',
          validationMessages: (control) =>
              {'required': 'Please enter the Product Brand'},
        ));
  }

  Widget groceryStoreTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Grocery Store',
          formControlName: GroceryItemFieldNames.groceryStore,
          hintText: 'Grocery Store...',
          validationMessages: (control) =>
              {'required': 'Please enter the Grocery Store'},
        ));
  }

  Widget descriptionTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          maxLength: 150,
          labelText: 'Description',
          formControlName: GroceryItemFieldNames.description,
          hintText: 'Description...',
          validationMessages: (control) =>
              {'required': 'Please enter the Product Description'},
        ));
  }

  Widget priceTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          textInputType: TextInputType.number,
          context: context,
          labelText: 'Price',
          formControlName: GroceryItemFieldNames.price,
          hintText: 'Price...',
          validationMessages: (control) =>
              {'required': 'Please enter the Product Price'},
        ));
  }

  Widget groceryItemCategoriesTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Categories',
          formControlName: GroceryItemFieldNames.groceryItemCategories,
          hintText: 'Categories...',
          validationMessages: (control) =>
              {'required': 'Please enter the Product Categories'},
        ));
  }

  Widget imageTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Image',
          formControlName: GroceryItemFieldNames.image,
          hintText: 'Image...',
          validationMessages: (control) =>
              {'required': 'Please enter the Product Image'},
        ));
  }
}

另一个策略buildFields:

class AddMenuItemStrategy implements AddVeganItemStrategy {
  List<Widget> buildFields({BuildContext context, FormGroup form}) {
    return [
      nameTextField(context: context, form: form),
      restaurantTextField(context: context),
      descriptionTextField(context: context),
      priceTextField(context: context),
      //   menuItemCategoriesTextField(context: context, form: form),
      imageTextField(context: context),
    ];
  }

  Widget nameTextField(
      {BuildContext context, FormGroup form, String nextField}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_4, PAD_3_HALF, PAD_4),
        child: VpTextField(
            context: context,
            labelText: 'Name',
            maxLength: 40,
            formControlName: MenuItemFieldNames.name,
            hintText: 'Name...',
            form: form,
            textInputAction: TextInputAction.next,
            nextField: nextField,
            validationMessages: (control) => {
                  'required': 'Please enter the Product Name',
                }));
  }

  Widget restaurantTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Restaurant',
          formControlName: MenuItemFieldNames.restaurant,
          hintText: 'Restaurant...',
          validationMessages: (control) =>
              {'required': 'Please enter the Restaurant'},
        ));
  }

  Widget descriptionTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          maxLength: 150,
          labelText: 'Description',
          formControlName: MenuItemFieldNames.description,
          hintText: 'Description...',
          validationMessages: (control) =>
              {'required': 'Please enter the Menu Item Description'},
        ));
  }

  Widget priceTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          textInputType: TextInputType.number,
          context: context,
          labelText: 'Price',
          formControlName: MenuItemFieldNames.price,
          hintText: 'Price...',
          validationMessages: (control) =>
              {'required': 'Please enter the Menu Item Price'},
        ));
  }

  Widget menuItemCategoriesTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Categories',
          formControlName: MenuItemFieldNames.menuItemCategories,
          hintText: 'Categories...',
          validationMessages: (control) =>
              {'required': 'Please enter the Menu Item Categories'},
        ));
  }

  Widget imageTextField({BuildContext context}) {
    return Container(
        padding:
            const EdgeInsets.fromLTRB(PAD_3_HALF, PAD_0, PAD_3_HALF, PAD_4),
        child: VpTextField(
          context: context,
          labelText: 'Image',
          formControlName: MenuItemFieldNames.image,
          hintText: 'Image...',
          validationMessages: (control) =>
              {'required': 'Please enter the Menu Item Image'},
        ));
  }

我想我和你有类似的问题。我通过向我的 ReactiveTextField 添加一个键来解决它。
在这里你可以看到我的问题https://github.com/joanpablo/reactive_forms/issues/66