在 flutter 中从 EventSink 中删除错误
removing errors from EventSink in flutter
我从 flutter 应用程序中得到了奇怪的行为,试图解决这个问题两天...
- 如果我在热重启后立即尝试提交登录表单(空白字段)-> 错误:字段为空-> 然后我填写表单,我将再次尝试重新提交,一切正常。
- 如果我在没有提交空表单的情况下进行热重启并填写登录表单,提交按钮将永远不会将数据发送到服务器。由于现有的 EventSink 错误,由于某种原因在第一种情况下不会出现。
代码如下:
表单小部件:
@override
Widget build(BuildContext context) {
final FormBloc formBloc = FormProvider.of(context);
Widget _emailField(FormBloc formBloc) {
return StreamBuilder(
stream: formBloc.email,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextFormField(
autofocus: false,
keyboardType: TextInputType.emailAddress,
onChanged: formBloc.changeEmail,
Widget _passwordField(FormBloc formBloc) {
return StreamBuilder(
stream: formBloc.password,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextFormField(
autofocus: false,
obscureText: !_passwordVisible,
keyboardType: TextInputType.text,
onChanged: formBloc.changePassword,
Formbloc:
class FormBloc with LoginValidationMixin {
final _email = BehaviorSubject<String>();
final _password = BehaviorSubject<String>();
final _errorMessage = BehaviorSubject<String>();
// getters
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
Function(String) get addError => _errorMessage.sink.add;
// streams
Stream<String> get email => _email.stream.transform(validatorEmail);
Stream<String> get password => _password.stream.transform(validatorPassword);
Stream<String> get errorMessage => _errorMessage.stream;
Stream<bool> get submitValidForm => Rx.combineLatest3(
email,
password,
errorMessage,
(e, p, er) => true,
);
late AuthService authInfo;
// login
dynamic login(BuildContext context) async {
authInfo = AuthService();
final email = _email.valueOrNull;
final password = _password.valueOrNull;
if (email == null || password == null) {
addError("Password or Email cannot be empty");
return;
}
final response =
await authInfo.login(email, password, this);
if (response == null) {return;}
final data = jsonDecode(response) as Map<String, dynamic>;
if (data['status_code'] != 200) {
} else {
final tokens = data['tokens'];
AuthService.setToken(
tokens["access"], tokens["refresh"], data['client_id']);
Navigator.pushNamed(context, '/home');
return data;
}
}
验证
class LoginValidationMixin {
static String get passwordPattern => "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}";
final validatorEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (email, sink) {
sink.add(email);
if (!EmailValidator.validate(email)) {
sink.addError('Email should look like:'
'welcome@itsy.ext\n');
} else {
sink.add(email);
}
},
);
final validatorPassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
sink.add(password);
if (!RegExp(passwordPattern).hasMatch(password)) {
sink.addError('A hint, password should contain\n'
'at least 8 characters\n'
'at least 1 upper case character\n'
'at least 1 upper case character\n'
'at least 1 numerical character\n');
} else {
sink.add(password);
}
},
);
}
登录按钮
Widget _loginButton(FormBloc formBloc) {
return StreamBuilder<bool>(
stream: formBloc.submitValidForm,
builder: (context, AsyncSnapshot<bool> snapshot) {
return Material(
child: MaterialButton(
onPressed: () {
if (snapshot.error != null) {
print(snapshot.error) <<<< in the second scenario, here is always an error, even if filed validations have passed. While in the first scenario, this does work as expected.
return;
} else {
formBloc.login(context);
}
},
所以,在第二种情况下,EventSink一直报错,按钮基本无法点击。但是,在第一种情况下,EventSink 工作正常,如果有错误则保留错误,如果添加了正确的值则清除它们。我应该怎么办?有没有办法清除 EventSink 错误?
这就是我解决这个问题的方法,首先我意识到流只会产生价值而不是存储。
pskink: EvenSink does not hold an error
Next, I checked that
Stream<bool> get submitValidForm => Rx.combineLatest3(
email,
password,
errorMessage, <<< this one is null in the case two, therefore my solution was to give it an initial value while handling email or password.
(e, p, er) => true,
);
我从 flutter 应用程序中得到了奇怪的行为,试图解决这个问题两天...
- 如果我在热重启后立即尝试提交登录表单(空白字段)-> 错误:字段为空-> 然后我填写表单,我将再次尝试重新提交,一切正常。
- 如果我在没有提交空表单的情况下进行热重启并填写登录表单,提交按钮将永远不会将数据发送到服务器。由于现有的 EventSink 错误,由于某种原因在第一种情况下不会出现。
代码如下: 表单小部件:
@override
Widget build(BuildContext context) {
final FormBloc formBloc = FormProvider.of(context);
Widget _emailField(FormBloc formBloc) {
return StreamBuilder(
stream: formBloc.email,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextFormField(
autofocus: false,
keyboardType: TextInputType.emailAddress,
onChanged: formBloc.changeEmail,
Widget _passwordField(FormBloc formBloc) {
return StreamBuilder(
stream: formBloc.password,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextFormField(
autofocus: false,
obscureText: !_passwordVisible,
keyboardType: TextInputType.text,
onChanged: formBloc.changePassword,
Formbloc:
class FormBloc with LoginValidationMixin {
final _email = BehaviorSubject<String>();
final _password = BehaviorSubject<String>();
final _errorMessage = BehaviorSubject<String>();
// getters
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
Function(String) get addError => _errorMessage.sink.add;
// streams
Stream<String> get email => _email.stream.transform(validatorEmail);
Stream<String> get password => _password.stream.transform(validatorPassword);
Stream<String> get errorMessage => _errorMessage.stream;
Stream<bool> get submitValidForm => Rx.combineLatest3(
email,
password,
errorMessage,
(e, p, er) => true,
);
late AuthService authInfo;
// login
dynamic login(BuildContext context) async {
authInfo = AuthService();
final email = _email.valueOrNull;
final password = _password.valueOrNull;
if (email == null || password == null) {
addError("Password or Email cannot be empty");
return;
}
final response =
await authInfo.login(email, password, this);
if (response == null) {return;}
final data = jsonDecode(response) as Map<String, dynamic>;
if (data['status_code'] != 200) {
} else {
final tokens = data['tokens'];
AuthService.setToken(
tokens["access"], tokens["refresh"], data['client_id']);
Navigator.pushNamed(context, '/home');
return data;
}
}
验证
class LoginValidationMixin {
static String get passwordPattern => "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}";
final validatorEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (email, sink) {
sink.add(email);
if (!EmailValidator.validate(email)) {
sink.addError('Email should look like:'
'welcome@itsy.ext\n');
} else {
sink.add(email);
}
},
);
final validatorPassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
sink.add(password);
if (!RegExp(passwordPattern).hasMatch(password)) {
sink.addError('A hint, password should contain\n'
'at least 8 characters\n'
'at least 1 upper case character\n'
'at least 1 upper case character\n'
'at least 1 numerical character\n');
} else {
sink.add(password);
}
},
);
}
登录按钮
Widget _loginButton(FormBloc formBloc) {
return StreamBuilder<bool>(
stream: formBloc.submitValidForm,
builder: (context, AsyncSnapshot<bool> snapshot) {
return Material(
child: MaterialButton(
onPressed: () {
if (snapshot.error != null) {
print(snapshot.error) <<<< in the second scenario, here is always an error, even if filed validations have passed. While in the first scenario, this does work as expected.
return;
} else {
formBloc.login(context);
}
},
所以,在第二种情况下,EventSink一直报错,按钮基本无法点击。但是,在第一种情况下,EventSink 工作正常,如果有错误则保留错误,如果添加了正确的值则清除它们。我应该怎么办?有没有办法清除 EventSink 错误?
这就是我解决这个问题的方法,首先我意识到流只会产生价值而不是存储。
pskink: EvenSink does not hold an error Next, I checked that
Stream<bool> get submitValidForm => Rx.combineLatest3(
email,
password,
errorMessage, <<< this one is null in the case two, therefore my solution was to give it an initial value while handling email or password.
(e, p, er) => true,
);