13

我正在寻找一个如何在 GetX 的最佳实践中处理表单和验证的示例?有没有什么好的例子,或者有人可以告诉我一个我们如何最好地做到这一点的例子吗?

4

2 回答 2

13

这是一个如何使用 GetX 的 observables 动态更新表单字段和提交按钮的示例。

我没有声称这是最佳实践。我敢肯定有更好的方法来完成同样的事情。但是玩弄如何使用 GetX 来执行验证是很有趣的。

表格 + Obx

基于 Observable 值变化重建的两个感兴趣的小部件:

  1. 文本表单域
    • InputDecoration 的errorText变化 & 将重建这个小部件
    • onChanged: fx.usernameChanged不会导致重建。usernameChanged(String val)当表单字段输入更改时,这将调用控制器中的函数。
    • 它只是username用一个新值更新 observable。
    • 可以写成:
    • onChanged: (val) => fx.username.value = val
  2. ElevatedButton(“提交”按钮)
    • onPressed函数可以在null和函数之间改变
    • null禁用按钮(在 Flutter 中这样做的唯一方法)
    • 此处的功能将启用按钮
class FormObxPage extends StatelessWidget {
  const FormObxPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    FormX fx = Get.put(FormX()); // controller

    return Scaffold(
      appBar: AppBar(
        title: const Text('Form Validation'),
      ),
      body: SafeArea(
        child: Container(
          alignment: Alignment.center,
          margin: const EdgeInsets.symmetric(horizontal: 5),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Obx(
                    () {
                  print('rebuild TextFormField ${fx.errorText.value}');
                  return TextFormField(
                      onChanged: fx.usernameChanged, // controller func
                      decoration: InputDecoration(
                          labelText: 'Username',
                          errorText: fx.errorText.value // obs
                      )
                  );
                },
              ),
              Obx(
                    () => ElevatedButton(
                  child: const Text('Submit'),
                  onPressed: fx.submitFunc.value, // obs
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

GetX 控制器

解释/分解如下

class FormX extends GetxController {
  RxString username = RxString('');
  RxnString errorText = RxnString(null);
  Rxn<Function()> submitFunc = Rxn<Function()>(null);

  @override
  void onInit() {
    super.onInit();
    debounce<String>(username, validations, time: const Duration(milliseconds: 500));
  }

  void validations(String val) async {
    errorText.value = null; // reset validation errors to nothing
    submitFunc.value = null; // disable submit while validating
    if (val.isNotEmpty) {
      if (lengthOK(val) && await available(val)) {
        print('All validations passed, enable submit btn...');
        submitFunc.value = submitFunction();
        errorText.value = null;
      }
    }
  }

  bool lengthOK(String val, {int minLen = 5}) {
    if (val.length < minLen) {
      errorText.value = 'min. 5 chars';
      return false;
    }
    return true;
  }

  Future<bool> available(String val) async {
    print('Query availability of: $val');
    await Future.delayed(
        const Duration(seconds: 1),
            () => print('Available query returned')
    );

    if (val == "Sylvester") {
      errorText.value = 'Name Taken';
      return false;
    }
    return true;
  }

  void usernameChanged(String val) {
    username.value = val;
  }

  Future<bool> Function() submitFunction() {
    return () async {
      print('Make database call to create ${username.value} account');
      await Future.delayed(const Duration(seconds: 1), () => print('User account created'));
      return true;
    };
  }
}

可观察的

从三个 observables 开始......

  RxString username = RxString('');
  RxnString errorText = RxnString(null);
  Rxn<Function()> submitFunc = Rxn<Function()>(null);

username将保存上次输入到 TextFormField 的内容。

errorTextnull初始值实例化,因此用户名字段不是“无效”的。如果为 null(甚至是空字符串),TextFormField 将呈现红色以表示无效输入。当字段中有无效输入时,我们将显示错误消息。(min. 5 chars例如:)

用户名太短

submitFunc是持有提交按钮函数的 observable 或null,因为 Dart 中的函数实际上是对象,这很好。初始null赋值将禁用该按钮。

初始化

工作人员在可观察端发生更改后 500 毫秒debounce调用该函数。validationsusername

validations将接收username.value作为它的参数。

更多关于工人

验证

validations函数内部,我们放置了我们想要运行的任何类型的验证:最小长度、坏字符、已经使用的名字、我们个人因童年欺凌而不喜欢的名字等。

为了增加真实感,available()函数是async. 通常这会查询数据库以检查用户名可用性,因此在此示例中,在返回此验证检查之前存在 1 秒的虚假延迟。

submitFunction()submitFunc返回一个函数,当我们确信表单具有有效输入并且我们允许用户继续时,它将替换 observable 中的 null 值。

更现实一点,我们会怀疑。期望提交按钮函数有一些返回值,所以我们可以让按钮函数返回一个未来的布尔值:

  Future<bool> Function() submitFunction() {
    return () async {
      print('Make database call to create ${username.value} account');
      await Future.delayed(Duration(seconds: 1), () => print('User account created'));
      return true;
    };
  }
于 2020-12-18T23:16:31.747 回答
12

GetX 不是万能的解决方案,但它有一些实用方法可以帮助您实现您想要的。例如,您可以使用validatorwith withSnackBar进行最终检查。这是一个代码片段,可以帮助您了解基础知识。

TextFormField(
  controller: emailController,
  autovalidateMode: AutovalidateMode.onUserInteraction,
  validator: (value) {
    if (!GetUtils.isEmail(value))
      return "Email is not valid";
    else
      return null;
  },               
),

GetUtils有几个方便的快速验证方法,你必须探索每种方法,看看它是否适合你的需要。

于 2020-12-16T12:49:51.817 回答