Flutter 条件渲染 2 个表单 - 将表单值复制到另一个表单

Posted

技术标签:

【中文标题】Flutter 条件渲染 2 个表单 - 将表单值复制到另一个表单【英文标题】:Flutter conditional rendering of 2 forms - duplicates the form values to the other form 【发布时间】:2021-01-30 09:45:42 【问题描述】:

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

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

  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',
        ));
  

【问题讨论】:

【参考方案1】:

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

【讨论】:

谢谢!像魅力一样工作。

以上是关于Flutter 条件渲染 2 个表单 - 将表单值复制到另一个表单的主要内容,如果未能解决你的问题,请参考以下文章

为啥条件渲染不适用于 vuejs 中的表单输入

Django 模板根据条件渲染每个表单字段

未处理有条件渲染组件中的表单提交

未处理有条件渲染组件中的表单提交

django 将view视图中的对象传入forms表单验证模块中

react 表单组件 异步渲染,值不会生效,需要手动改变对应组件的显示值