Flutter GetX表单验证 可观察的onInit验证

如何解决Flutter GetX表单验证 可观察的onInit验证

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

解决方法

这里有一个示例,说明如何使用 GetX 的 observable 动态更新表单字段和提交按钮。

我不声称这是最佳做法。我相信有更好的方法来完成同样的事情。但是尝试使用 GetX 来执行验证很有趣。

表单 + 对象

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

  1. TextFormField
    • InputDecoration 的 errorText 更改并将重建此小部件
    • onChanged: fx.usernameChanged 不会导致重建。这会在表单字段输入更改时调用控制器 usernameChanged(String val) 中的函数。
    • 它只是用新值更新 username observable。
    • 可以写成:
    • onChanged: (val) => fx.username.value = val
  2. RaisedButton(一个“提交”按钮)
    • onPressed 函数可以在 null 和函数之间切换
    • null 禁用按钮(Flutter 中唯一的方法)
    • 这里的一个函数将启用按钮
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    FormX fx = Get.put(FormX()); // controller

    return Scaffold(
      appBar: AppBar(
        title: Text('Form Validation'),),body: SafeArea(
        child: Container(
          alignment: Alignment.center,margin: 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(
                () => RaisedButton(
                  child: Text('Submit'),onPressed: fx.submitFunc.value,// obs
                ),)
            ],);
  }
}

GetX 控制器

解释/分解如下

class FormX extends GetxController {
  RxString username = ''.obs;
  RxString errorText = RxString(null);
  Rx<Function> submitFunc = Rx<Function>(null);

  @override
  void onInit() {
    super.onInit();
    debounce(username,validations,time: 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(
        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(Duration(seconds: 1),() => print('User account created'));
      return true;
    };
  }
}

可观察的

从三个 observable 开始......

  RxString username = ''.obs;
  RxString errorText = RxString(null);
  Rx<Function> submitFunc = Rx<Function>(null);

username 将保存最后输入到 TextFormField 中的任何内容。

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

username too short

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

onInit

debounce 工作线程在更改 validations 可观察端 500 毫秒后调用 username 函数。

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

More on workers

验证

validations 函数中,我们放置了我们想要运行的任何类型的验证:最小长度、坏字符、已取的名字、由于童年欺凌而导致我们个人不喜欢的名字等。

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

submitFunction() 返回一个函数,当我们对表单具有有效输入感到满意并允许用户继续时,该函数将替换 submitFunc observable 中的空值。

更现实一点,我们可能会。期待提交按钮函数的一些返回值,所以我们可以让按钮函数返回一个future bool:

  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;
    };
  }
,

在这里看看

class LoginController extends GetxController{
  TextEditingController email = TextEditingController();
  TextEditingController password = TextEditingController();
  
  void doLogin() {
    if (email.text.isEmpty) {
      errorSnackbar(msg: 'Enter Email Address');
    } else if (password.text.isEmpty) {
      errorSnackbar(msg: 'Enter Password');
    } else if (password.text.length < 6) {
      errorSnackbar(msg: "Password must be 6 digit");
    } else {
     // requestLogin();
    }
  }

  void errorSnackbar({@required String msg}) {
    return Get.snackbar(
        '$msg',"Error !",snackPosition: SnackPosition.TOP,backgroundColor: Colors.red[200],colorText: Colors.white
    );
  }
}
,

GetX并不能解决所有问题,但是它具有一些实用程序方法可以帮助您实现所需的目标。例如,您可以将validatorSnackBar一起使用进行最终检查。这是一个代码段,可以帮助您了解基础知识。

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

GetUtils几乎没有用于快速验证的便捷方法,您将不得不探索每种方法以查看其是否适合您的需求。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-