Flutter GetX 表单验证
Flutter GetX forms validation
我正在寻找有关如何使用 GetX 在最佳实践中处理表单和验证的示例?
有什么好的例子吗?或者有人可以告诉我我们如何最好地做到这一点的例子吗?
GetX 不是万能的解决方案,但它有一些实用方法可以帮助您实现您想要的。例如,您可以使用 validator
和 SnackBar
进行最终检查。这是一个代码片段,可以帮助您了解基础知识。
TextFormField(
controller: emailController,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (!GetUtils.isEmail(value))
return "Email is not valid";
else
return null;
},
),
GetUtils
没有几个方便的快速验证方法,您必须探索每种方法,看看它是否适合您的需要。
这是一个示例,说明如何使用 GetX 的可观察对象动态更新表单字段和提交按钮。
我不认为这是最佳做法。我相信有更好的方法可以实现同样的目标。但是研究如何使用 GetX 执行验证很有趣。
表格 + Obx
根据 Observable 值变化重建的两个感兴趣的小部件:
- TextFormField
- InputDecoration 的
errorText
更改并将重建此小部件
onChanged: fx.usernameChanged
不会导致重建。当表单字段输入更改时,这会调用控制器中的函数 usernameChanged(String val)
。
- 它只是用一个新值更新
username
observable。
- 可以写成:
onChanged: (val) => fx.username.value = val
- 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;
};
}
}
观察结果
从三个可观察量开始...
RxString username = RxString('');
RxnString errorText = RxnString(null);
Rxn<Function()> submitFunc = Rxn<Function()>(null);
username
将保存最后输入到 TextFormField 中的任何内容。
errorText
以 null
初始值实例化,因此用户名字段不是“无效”的。如果 not null(即使是空字符串),TextFormField 将呈现红色以表示无效输入。当字段中的输入无效时,我们将显示一条错误消息。 (例如 min. 5 chars
:)
submitFunc
是一个用于保存提交按钮函数或 null
的可观察对象,因为 Dart 中的函数实际上是对象,这很好。 null
值初始分配将禁用按钮。
onInit
debounce
工作人员在更改 username
可观察端后 500 毫秒调用 validations
函数。
validations
将接收 username.value
作为其参数。
验证
在 validations
函数中,我们放置了我们想要的任何类型的验证 运行:最小长度、错误字符、已使用的名字、我们个人不喜欢的名字(由于童年欺凌)等
为了增加真实感,available()
函数是 async
。通常这会查询数据库以检查用户名可用性,因此在此示例中,在 return 进行此验证检查之前有一个虚假的 1 秒延迟。
submitFunction()
returns 一个函数,当我们对表单具有有效输入感到满意并且我们允许用户继续时,它将替换 submitFunc
中可观察到的空值。
我们可能会更现实一点。期望提交按钮函数有一些 return 值,所以我们可以让按钮函数 return 成为未来的 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;
};
}
我正在寻找有关如何使用 GetX 在最佳实践中处理表单和验证的示例? 有什么好的例子吗?或者有人可以告诉我我们如何最好地做到这一点的例子吗?
GetX 不是万能的解决方案,但它有一些实用方法可以帮助您实现您想要的。例如,您可以使用 validator
和 SnackBar
进行最终检查。这是一个代码片段,可以帮助您了解基础知识。
TextFormField(
controller: emailController,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (!GetUtils.isEmail(value))
return "Email is not valid";
else
return null;
},
),
GetUtils
没有几个方便的快速验证方法,您必须探索每种方法,看看它是否适合您的需要。
这是一个示例,说明如何使用 GetX 的可观察对象动态更新表单字段和提交按钮。
我不认为这是最佳做法。我相信有更好的方法可以实现同样的目标。但是研究如何使用 GetX 执行验证很有趣。
表格 + Obx
根据 Observable 值变化重建的两个感兴趣的小部件:
- TextFormField
- InputDecoration 的
errorText
更改并将重建此小部件 onChanged: fx.usernameChanged
不会导致重建。当表单字段输入更改时,这会调用控制器中的函数usernameChanged(String val)
。- 它只是用一个新值更新
username
observable。 - 可以写成:
onChanged: (val) => fx.username.value = val
- InputDecoration 的
- 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;
};
}
}
观察结果
从三个可观察量开始...
RxString username = RxString('');
RxnString errorText = RxnString(null);
Rxn<Function()> submitFunc = Rxn<Function()>(null);
username
将保存最后输入到 TextFormField 中的任何内容。
errorText
以 null
初始值实例化,因此用户名字段不是“无效”的。如果 not null(即使是空字符串),TextFormField 将呈现红色以表示无效输入。当字段中的输入无效时,我们将显示一条错误消息。 (例如 min. 5 chars
:)
submitFunc
是一个用于保存提交按钮函数或 null
的可观察对象,因为 Dart 中的函数实际上是对象,这很好。 null
值初始分配将禁用按钮。
onInit
debounce
工作人员在更改 username
可观察端后 500 毫秒调用 validations
函数。
validations
将接收 username.value
作为其参数。
验证
在 validations
函数中,我们放置了我们想要的任何类型的验证 运行:最小长度、错误字符、已使用的名字、我们个人不喜欢的名字(由于童年欺凌)等
为了增加真实感,available()
函数是 async
。通常这会查询数据库以检查用户名可用性,因此在此示例中,在 return 进行此验证检查之前有一个虚假的 1 秒延迟。
submitFunction()
returns 一个函数,当我们对表单具有有效输入感到满意并且我们允许用户继续时,它将替换 submitFunc
中可观察到的空值。
我们可能会更现实一点。期望提交按钮函数有一些 return 值,所以我们可以让按钮函数 return 成为未来的 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;
};
}