fir*_*han 7 dart flutter rxdart bloc
我想创建一个 TextField 来检查数据库中是否存在该值。
如何使用带TextField
小部件的BLOC 模式进行异步验证?我应该使用StreamTransformer
将错误添加到Stream
? 我尝试使用,DebounceStreamTransformer
但它只是阻止Stream
接收新值。
这是我的 Observable
Observable<String> get valueStream => valueController.stream.transform(PropertyNameExist.handle('Blabla', null));
Run Code Online (Sandbox Code Playgroud)
这是我的 StreamTransformer
class PropertyNameExist implements StreamTransformerValidator {
static StreamTransformer<String, String> handle(String fieldname, String data) {
Http http = new Http();
return StreamTransformer<String, String>.fromHandlers(
handleData: (String stringData, sink) {
http.post('/my_api',data:{
'property_name':stringData,
}).then((Response response){
Map<String,dynamic> responseData = jsonDecode(response.data);
bool isValid = responseData['valid'] == 'true';
if(isValid){
sink.add(stringData);
} else {
sink.addError('Opps Error');
}
});
});
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的 Widget
StreamBuilder<String>(
stream: valueStream,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
_textInputController.setTextAndPosition(snapshot.data);
}
return TextField(
controller: _textInputController,
onChanged: (String newVal) {
updateValue(newVal);
},
decoration: InputDecoration(
errorText: snapshot.error,
),
);
},
)
Run Code Online (Sandbox Code Playgroud)
您可能不再寻找解决方案,而是基于我想提供答案的问题的赞成票。
我不确定我是否正确理解了您的代码,并且看起来您正在自己实现 BLoC,所以这是一个免责声明,因为我提供了一个使用 Felix Angelov 的 BLoC 实现的解决方案(pub.dev/packages/bloc) .
下面描述的代码的结果
代码和方法:
首先我创建了一个空项目,并添加了 BLoC 库;在pubspec.yaml
我添加
flutter_bloc: ^3.2.0
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个BackendValidationBloc
包含一个事件ValidateInput
和多个状态的新块,如下面的代码片段所示。
事件代码:
大多数情况下,我首先定义在我的示例中非常简单的事件:
part of 'backend_validation_bloc.dart';
@immutable
abstract class BackendValidationEvent {}
class ValidateInput extends BackendValidationEvent {
final String input;
ValidateInput({@required this.input});
}
Run Code Online (Sandbox Code Playgroud)
州代码:
那么您可能想要一个具有多个属性或多个状态的状态。我决定使用具有多个属性的一种状态,因为在我看来它更容易在 UI 中处理。在这个例子中,我建议向用户提供反馈,因为通过后端验证输入可能需要一些时间。因此BackendValidationState
具有两种状态:loading
和validated
。
part of 'backend_validation_bloc.dart';
@immutable
class BackendValidationState {
final bool isInProcess;
final bool isValidated;
bool get isError => errorMessage.isNotEmpty;
final String errorMessage;
BackendValidationState(
{this.isInProcess, this.isValidated, this.errorMessage});
factory BackendValidationState.empty() {
return BackendValidationState(
isInProcess: false, isValidated: false);
}
BackendValidationState copyWith(
{bool isInProcess, bool isValidated, String errorMessage}) {
return BackendValidationState(
isValidated: isValidated ?? this.isValidated,
isInProcess: isInProcess ?? this.isInProcess,
// This is intentionally not defined as
// errorMessage: errorMessage ?? this.errorMessage
// because if the errorMessage is null, it means the input was valid
errorMessage: errorMessage,
);
}
BackendValidationState loading() {
return this.copyWith(isInProcess: true);
}
BackendValidationState validated({@required String errorMessage}) {
return this.copyWith(errorMessage: errorMessage, isInProcess: false);
}
}
Run Code Online (Sandbox Code Playgroud)
区块代码:
最后,您通过定义调用后端的 bloc 将事件与状态“连接”:
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';
part 'backend_validation_event.dart';
part 'backend_validation_state.dart';
class BackendValidationBloc
extends Bloc<BackendValidationEvent, BackendValidationState> {
@override
BackendValidationState get initialState => BackendValidationState.empty();
@override
Stream<BackendValidationState> mapEventToState(
BackendValidationEvent event,
) async* {
if (event is ValidateInput) {
yield this.state.loading();
String backendValidationMessage =
await this.simulatedBackendFunctionality(event.input);
yield this.state.validated(errorMessage: backendValidationMessage);
}
}
Future<String> simulatedBackendFunctionality(String input) async {
// This simulates delay of the backend call
await Future.delayed(Duration(milliseconds: 500));
// This simulates the return of the backend call
String backendValidationMessage;
if (input != 'hello') {
backendValidationMessage = "Input does not equal to 'hello'";
}
return backendValidationMessage;
}
}
Run Code Online (Sandbox Code Playgroud)
界面代码:
如果您不熟悉如何在 UI 中使用实现的 BLoC,这是前端代码使用状态将不同的值(用于实际错误消息和等待后端响应时的用户反馈)提供给 errorText 属性的TextField
。
import 'package:backend_validation_using_bloc/bloc/backend_validation_bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider<BackendValidationBloc>(
create: (context) => BackendValidationBloc(), child: HomeScreen()),
);
}
}
class HomeScreen extends StatefulWidget {
HomeScreen({Key key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TextEditingController textEditingController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: BlocBuilder<BackendValidationBloc, BackendValidationState>(
builder: (BuildContext context, BackendValidationState state) {
return TextField(
controller: textEditingController,
onChanged: (String currentValue) {
BlocProvider.of<BackendValidationBloc>(context)
.add(ValidateInput(input: currentValue));
},
decoration: InputDecoration(errorText: state.isInProcess ? 'Valiating input...' : state.errorMessage),
);
},
));
}
}
Run Code Online (Sandbox Code Playgroud)
连接真实的后端
所以我有点伪造了一个后端,但是如果你想使用一个真正的后端,通常会实现 aRepository
并将它传递给BLoC
构造函数中的 ,这使得使用不同的后端实现更容易(如果针对接口正确实现)。如果您想要更详细的教程,请查看Felix Angelov 的教程(它们非常好)
希望这可以帮助您或其他人。
归档时间: |
|
查看次数: |
3739 次 |
最近记录: |