【问题标题】:Trigger a validate/submit form method from the AppBar in flutter在 Flutter 中从 AppBar 触发验证/提交表单方法
【发布时间】:2020-12-21 17:44:54
【问题描述】:

我有 3 个小部件。

HomeApp - 连接一切的无状态小部件。
A custom AppBarWidget - 一个有提交按钮的有状态小部件。
A SurveyForm 小部件 - 一个有状态的小部件,有 50 多个输入,包括 TextFormField、单选按钮和一大堆自定义输入类型。

当用户按下appbar中的提交按钮时,它需要在调查表单中做一些自定义验证,创建一个新的模型类。将其转换为 JSON 对象,并将 POST 发送到 API。

我已经阅读了一些选项,

  1. 在 HomeApp 中启动所有变量和验证/提交逻辑,将其传递给 SurveyForm,并使用回调触发函数。但这涉及到我将 50 多个参数传递给 SurveyForm。
  2. 使用全局密钥。不太确定它是如何工作的,当我尝试做final key = new GlobalKey<SurveyForm>(); 时,它说'SurveyForm' doesn't extend 'State<StatefulWidget>'.
  3. 将父实例传递给子小部件,由this link 建议。
  4. 调用子部件的方法,但this link表示不鼓励。
  5. 编写自定义控制器。

在 Flutter 中更可取的方式是什么?

【问题讨论】:

  • 您是否在单独的文件中尝试了静态值?您还可以使用 BloC 模式并为您的两个小部件(应用栏和表单)使用相同的 bloc
  • 我认为 BlocC 模式可能是要走的路...

标签: flutter


【解决方案1】:

您可以使用表单小部件Tutorial。 基本上你用一个表单小部件包装你所有的文本字段和复选框和其他东西,并将它的键设置为GlobalKey<FormState>()。现在您可以在其中使用另一种类型的字段(例如,您可以使用 TextFormField 而不是 TextaField)现在您可以在它们上设置一个名为 onSaved 的属性(我们稍后会使用它)。然后,每当您想提交表单数据时,您都会调用您在状态类中编写的函数(通过将其添加到按钮的 onPressed 值)。是这样的:

void _submitForm() {
    final form = _formKey.currentState; // this is your GlobalKey<FormState> that you specified and set to the key of your Form Widget.
    if (form.validate()) { // form.validate() will call all the validator functions that you've passed to your inputfields
      form.save(); // This will call all the onSaved functions that you passed to your forms.
    }
}

它获取您的表单小部件,调用输入的所有验证器函数,如果一切都适合,则调用输入的所有 onSaved 函数。

您可以创建一个字典并在输入字段的 onSaved 中设置输入值。 现在您可以使用 json.encode(your_data_dict) 将其转换为 JSON 字符串或使用您的对象。然后发布json。

【讨论】:

  • 如何在单选按钮上使用表单小部件?我找不到任何例子。
  • 单选按钮不需要验证,只需尝试在其 onChanged 回调上操作您的数据字典。
  • 不需要或不能?我需要验证是否选择了一组单选按钮。我正在寻找将整个集合包装在 FormField 小部件中,但我无法弄清楚如何在 FormField 中触发“didChange”方法。
【解决方案2】:

所以我设法解决了这个问题。
我的问题实际上应该分解为 3 个问题。

  1. 验证文本表单字段、单选按钮、所有自定义输入。
  2. 创建一个可以传递转换为 JSON 的新模型类。
  3. 从另一个小部件(Appbar)中的按钮提交表单。

为了解决第一个问题,我将 SurveyForm 中的所有内容都包装到了一个 Form 小部件中。这部分很简单,网上有很多教程。为了对自定义输入进行验证,我将输入包装在一个FormField 小部件中,并触发FormFieldStatedidChange 方法。这允许我使用方法callback 使用FormFieldvalidatoronSaved 方法。下面是我的日期选择器工作代码。

class Q1<T> extends StatefulWidget {
  final FormFieldValidator<DateTime> validator;
  final FormFieldSetter<DateTime> onSaved;

  const Q1({
    Key key,
    @required this.onSaved,
    @required this.validator,
  })  : assert(validator != null),
        assert(onSaved != null),
        super(
          key: key,
        );

  @override
  _Q1State createState() => _Q1State();
}

class _Q1State extends State<Q1> {
  DateTime _completionDate;

  @override
  Widget build(BuildContext context) {
    return FormField(
      validator: (val) {
        return widget.validator(val);
      },
      onSaved: (val) {
        widget.onSaved(val);
      },
      builder: (FormFieldState<dynamic> field) {
        return Row(
          children: [
            Expanded(
              flex: 1,
              child: Text('1. Completion Date'),
            ),
            Expanded(
              flex: 2,
              child: Row(
                children: [
                  Container(
                    padding: EdgeInsets.all(
                      SizeConfig().getProportionateScreenWidth(
                          kDatePickerIconTextBoxPadding),
                    ),
                    decoration: BoxDecoration(
                      border: Border.all(
                        color: kDatePickerIconTextBoxBorderColor,
                      ),
                      borderRadius: BorderRadius.all(Radius.circular(
                        SizeConfig().getProportionateScreenWidth(
                            kDatePickerIconTextBoxRadius),
                      ) //         <--- border radius here
                          ),
                    ),
                    child: Text(_completionDate == null
                        ? 'Pick a date'
                        : DateFormat(kDateFormat).format(_completionDate)),
                  ),
                  IconButton(
                      onPressed: () {
                        showDatePicker(
                          context: context,
                          initialDate: DateTime.now(),
                          firstDate: DateTime(2000),
                          lastDate: DateTime(2100),
                        ).then((date) {
                          setState(() {
                            field.didChange(date);
                            _completionDate = date;
                          });
                        });
                      },
                      icon: FaIcon(FontAwesomeIcons.calendarAlt)),
                ],
              ),
            ),
          ],
        );
      },
    );
  }
}

我只是用

调用了这个小部件
Q1(
              validator: (val) {
                if (val == null) {
                  return 'Completion Date is missing';
                }
                return null;
              },
              onSaved: (value) {
                setState(() {
                  widget.questionnaire.completion_date = DateFormat(kDateFormat).format(value);
                });
              },
            ),

为了解决第二个问题。我使用了json_serializable,该对象也可以在 HomeApp 和 SurveyForm 小部件之间传递,因此我不需要传递大约 50 多个变量。

对于第三个问题,我在 HomeApp 中发起final _formKey = GlobalKey&lt;FormState&gt;();,并将其传递给SurveyForm 小部件,并在Appbar 中使用onPressed 回调触发SurveyForm 中的验证/提交。

Bloc 将用于提交 JSON 和加载动画,但不限于此。

我是 Flutter 的新手(已经使用了一个月),如果有人有更好的解决方案,请告诉我。

【讨论】:

    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 2017-03-06
    • 2016-12-16
    • 2019-11-06
    • 1970-01-01
    • 2015-05-20
    • 2016-11-13
    • 1970-01-01
    相关资源
    最近更新 更多