使用flutter_bloc提交时如何验证表单?
Posted
技术标签:
【中文标题】使用flutter_bloc提交时如何验证表单?【英文标题】:How to validate form when submit in flutter with flutter_bloc? 【发布时间】:2020-06-02 07:02:26 【问题描述】:这是我的更改密码屏幕。我正在使用 flutter_bloc 来实现 mvvc 模式。此页面适用于 bloc。但我想要实现的是在提交表单时验证表单。由于我是新手,所以我不知道该怎么做。
更改密码事件
abstract class ChangePasswordEvent extends Equatable
const ChangePasswordEvent();
class SubmitButtonPressed extends ChangePasswordEvent
final String oldPassword;
final String newPassword;
const SubmitButtonPressed(@required this.oldPassword, this.newPassword);
@override
List<Object> get props => [oldPassword, newPassword];
更改密码状态
abstract class ChangePasswordState extends Equatable
const ChangePasswordState();
@override
List<Object> get props => [];
class ChangePasswordInitial extends ChangePasswordState
class ChangePasswordLoading extends ChangePasswordState
class ChangePasswordSuccess extends ChangePasswordState
class ChangePasswordFailure extends ChangePasswordState
final String error;
const ChangePasswordFailure(@required this.error);
@override
List<Object> get props => [error];
@override
String toString() => 'ChangePasswordFailure error: $error ';
更改密码区
class ChangePasswordBloc
extends Bloc<ChangePasswordEvent, ChangePasswordState>
final UserRepository userRepository;
ChangePasswordBloc(
@required this.userRepository,
) : assert(userRepository != null);
@override
ChangePasswordState get initialState => ChangePasswordInitial();
@override
Stream<ChangePasswordState> mapEventToState(
ChangePasswordEvent event) async*
if (event is SubmitButtonPressed)
yield ChangePasswordLoading();
try
final bool isPasswordChanged = await userRepository.changePassword(
event.oldPassword,
event.newPassword,
);
if (isPasswordChanged)
yield ChangePasswordSuccess();
catch (error)
yield ChangePasswordFailure(error: error);
更改密码页面
class ChangePasswordPage extends StatelessWidget
final UserRepository userRepository;
ChangePasswordPage(Key key, @required this.userRepository)
: assert(userRepository != null),
super(key: key);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('Change Password'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: BlocProvider(
create: (context)
return ChangePasswordBloc(
userRepository: userRepository,
);
,
child: ChangePasswordForm(),
),
),
);
更改密码表格
class ChangePasswordForm extends StatefulWidget
@override
_ChangePasswordFormState createState() => _ChangePasswordFormState();
class _ChangePasswordFormState extends State<ChangePasswordForm>
final userRepository = UserRepository();
final _formKey = GlobalKey<FormState>();
final _oldPassController = TextEditingController();
final _newPassController = TextEditingController();
final _confirmPassController = TextEditingController();
@override
Widget build(BuildContext context)
_onSubmitButtonPressed()
BlocProvider.of<ChangePasswordBloc>(context).add(
SubmitButtonPressed(
oldPassword: _oldPassController.text,
newPassword: _newPassController.text,
),
);
return BlocListener<ChangePasswordBloc, ChangePasswordState>(
listener: (context, state)
if (state is ChangePasswordFailure)
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('$state.error'),
backgroundColor: Colors.red,
),
);
if (state is ChangePasswordSuccess)
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Password Changed Successfully'),
backgroundColor: Colors.green,
),
);
,
child: BlocBuilder<ChangePasswordBloc, ChangePasswordState>(
builder: (context, state)
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Old Password'),
controller: _oldPassController,
),
SizedBox(height: 20.0),
TextFormField(
decoration: InputDecoration(labelText: 'New Password'),
controller: _newPassController,
obscureText: true,
),
SizedBox(height: 20.0),
TextFormField(
decoration: InputDecoration(labelText: 'Confirm Password'),
controller: _confirmPassController,
obscureText: true,
validator: (value)
final String _newPassword = _newPassController.text;
if (_newPassword != value)
return "Password Mismatch";
return null;
,
),
SizedBox(height: 20.0),
RaisedButton(
onPressed: ()
if (state is! ChangePasswordLoading)
final form = _formKey.currentState;
if (form.validate())
return _onSubmitButtonPressed();
return null;
,
child: Text('Submit'),
),
],
),
);
,
),
);
【问题讨论】:
您在提交_formKey.currentState.validate()
时对其进行验证。你的问题是什么?
结帐flutter_form_bloc,它有一个专为表单设计的bloc
,它将为您节省大量代码。
【参考方案1】:
你去看看他们的例子:Form Validation
该示例验证电子邮件和密码格式,您应该相应地更改它。你的状态应该是这样的:
class MyFormState extends Equatable
final String email;
final bool isEmailValid;
final String password;
final bool isPasswordValid;
final bool formSubmittedSuccessfully;
bool get isFormValid => isEmailValid && isPasswordValid;
//....
要验证的 BLoC:
class MyFormBloc extends Bloc<MyFormEvent, MyFormState>
final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&’*+/=?^_`|~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
final RegExp _passwordRegExp = RegExp(
r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]8,$',
);
@override
MyFormState get initialState => MyFormState.initial();
@override
void onTransition(Transition<MyFormEvent, MyFormState> transition)
print(transition);
@override
Stream<MyFormState> mapEventToState(
MyFormEvent event,
) async*
if (event is EmailChanged)
yield state.copyWith(
email: event.email,
isEmailValid: _isEmailValid(event.email),
);
if (event is PasswordChanged)
yield state.copyWith(
password: event.password,
isPasswordValid: _isPasswordValid(event.password),
);
if (event is FormSubmitted)
yield state.copyWith(formSubmittedSuccessfully: true);
if (event is FormReset)
yield MyFormState.initial();
bool _isEmailValid(String email)
return _emailRegExp.hasMatch(email);
bool _isPasswordValid(String password)
return _passwordRegExp.hasMatch(password);
以及Form构建方法:
@override
Widget build(BuildContext context)
return BlocBuilder<MyFormBloc, MyFormState>(
builder: (context, state)
if (state.formSubmittedSuccessfully)
return SuccessDialog(onDismissed: ()
_emailController.clear();
_passwordController.clear();
_myFormBloc.add(FormReset());
);
return Form(
child: Column(
children: <Widget>[
TextFormField(
controller: _emailController,
decoration: InputDecoration(
icon: Icon(Icons.email),
labelText: 'Email',
),
keyboardType: TextInputType.emailAddress,
autovalidate: true,
validator: (_)
return state.isEmailValid ? null : 'Invalid Email';
,
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: 'Password',
),
obscureText: true,
autovalidate: true,
validator: (_)
return state.isPasswordValid ? null : 'Invalid Password';
,
),
RaisedButton(
onPressed: state.isFormValid ? _onSubmitPressed : null,
child: Text('Submit'),
),
],
),
);
,
);
【讨论】:
【参考方案2】:我认为最好不要将 flutter_bloc 包用于验证目的,因为它会导致所有控件的重建。而是使用像这里描述的 Stream 和 Provider 这样的原始对象。 https://www.youtube.com/watch?v=JqWK4oitJFs
附加链接:https://medium.com/swlh/how-to-create-a-simple-login-form-in-flutter-using-bloc-pattern-b55ad52a2a10
【讨论】:
以上是关于使用flutter_bloc提交时如何验证表单?的主要内容,如果未能解决你的问题,请参考以下文章
当引导验证成功时,如何使用 $.post 提交表单而不进行页面重定向?