#dart #flutter #bloc #rxdart
#dart #флаттер #блок #rxdart
Вопрос:
У меня есть реактивная форма входа в систему, следующая шаблону БЛОКОВ. Я пытаюсь программно очистить все значения в нем. В моем блоке моя функция отправки передает пустые строки в мои потоковые приемники:
class Bloc with Validators {
final _email = BehaviorSubject<String>();
final _password = BehaviorSubject<String>();
Stream<String> get email => _email.stream.transform(validateEmail);
Stream<String> get password => _password.stream.transform(validatePassword);
Stream<bool> get submitValid => Observable.combineLatest2(email, password, (String e, String p) {
var valid = (e != null amp;amp; e.isNotEmpty)
amp;amp; (p != null amp;amp; p.isNotEmpty);
print('$e amp;amp; $p = $valid');
return valid;
});
Function(String) get changeEmail => _email.sink.add;
Function(String) get changePassword => _password.sink.add;
submit() {
final validEmail = _email.value;
final validPassword = _email.value;
print('final values: $validEmail amp;amp; $validPassword');
changeEmail('');
changePassword('');
}
dispose() {
_email.close();
_password.close();
}
}
Когда я нажимаю кнопку отправки, которая вызывает эту submit()
функцию, я получаю сообщения об ошибках для обоих текстовых полей, потому что значения электронной почты и пароля изменились за кулисами, но они визуально не обновляются в текстовых полях. Вот мои StreamBuilders для моих текстовых полей и кнопки отправки:
Widget emailField(Bloc bloc) {
return StreamBuilder(
stream: bloc.email,
builder: (context, snapshot) { // re-runs build function every time the stream emits a new value
return TextField(
onChanged: bloc.changeEmail,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
icon: Icon(Icons.email),
hintText: 'email address (you@example.com)',
labelText: 'Email',
errorText: snapshot.error
)
);
}
);
}
Widget passwordField(Bloc bloc) {
return StreamBuilder(
stream: bloc.password,
builder: (context, AsyncSnapshot<String> snapshot) {
return TextField(
onChanged: bloc.changePassword,
autocorrect: false,
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.security),
hintText: 'must be greater than 6 characters',
labelText: 'Password',
errorText: snapshot.error
)
);
}
);
}
Widget submitButton(Bloc bloc) {
return StreamBuilder(
stream: bloc.submitValid,
builder: (context, snapshot) {
return RaisedButton(
child: Text('Logins'),
color: Colors.blue,
onPressed: !snapshot.hasData || snapshot.hasError || snapshot.data == false
? null
: bloc.submit
);
}
);
}'
И вот код, который я использую для своих валидаторов в моем блоке:
class Validators {
final validateEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (email, sink) {
RegExp exp = new RegExp(r"^[a-zA-Z0-9.] @[a-zA-Z0-9] .[a-zA-Z] ");
var valid = exp.hasMatch(email);
if (valid) {
sink.add(email);
} else {
sink.add('');
sink.addError('Invalid email address!');
}
}
);
final validatePassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
var valid = password.length >= 6;
if (valid) {
sink.add(password);
} else {
sink.add('');
sink.addError('Password must be at least 6 characters long!');
}
}
);
}
В моих валидаторах я выдаю пустую строку всякий раз, когда возникает ошибка. Это делает так, что средство получения submitValid работает, когда пользователь делает недействительным то, что раньше было действительным.
Ответ №1:
Я знаю, что прошло много времени, но это мой способ решения проблемы.
Во-первых, я создал TextEditingController
для my TextField
. Затем я создал два метода в своем блоке: updateTextOnChanged
и updateTextElsewhere
. На первом я просто извлек значение (потому что оно мне нужно для последующего использования). Во втором я добавил приемник для обновления контроллера в текстовом поле.
Виджет:
return StreamBuilder<String>(
stream: bloc.streamText,
builder: (context, snapshot) {
_controller.text = snapshot.data;
return Expanded(
child: TextField(
controller: _controller,
onChanged: (value) => {bloc.updateTextOnChanged(value)},
),
);
}
);
Блок:
Stream<String> get streamText => _controllerTxt.stream;
String _myText;
void updateTextElsewhere(String value) {
_controllerTxt.sink.add(value);
}
void updateTextOnChanged(String value) {
_myText = value;
}
Тогда вам просто нужно вызывать updateTextElsewhere()
всякий раз, когда вам нужно обновить его вне OnChanged.
В вашем случае просто добавьте пустую строку, например: updateTextElsewhere("");
Ответ №2:
В submit () вы, похоже, сбрасываете имя пользователя и пароль
changeEmail('');
changePassword('');
И, как вы прокомментировали, «повторно запускает функцию сборки каждый раз, когда поток выдает новое значение». Он перестраивает пользовательский интерфейс, поскольку значение обновлено до пустого. Может быть, это вызывает проблему?
Комментарии:
1. Я не думаю, что это должно вызвать проблему. Он должен перестроить этот элемент пользовательского интерфейса с пустой строкой, но старое значение до того, как я передал пустые строки в приемники, все еще застряло в элементах пользовательского интерфейса. Однако сообщение об ошибке для элемента пользовательского интерфейса обновляется, чтобы отразить, как если бы ввод был пустым.