Reputation: 57
I have a TextFormField widget wrapped inside a StreamBuilder, in TextFormField widget, inside the decoration, when is pass snapshot.error to the errorText argument, it gives an error:
The argument type 'Object?' can't be assigned to the parameter type 'String?'
Here is the code for state class with form and TextFormField
class LoginScreen extends StatefulWidget{
State<StatefulWidget> createState() {
return _LoginScreen();
}
}
class _LoginScreen extends State<LoginScreen>{
final form_key = GlobalKey<FormState>();
Widget build(context){
return Container(
margin: EdgeInsets.all(20),
child: Form(
key: form_key,
child: Column(
children: [
emailField(),
passwordField(),
Padding(
padding: EdgeInsets.all(7),
child: submitButton(),
),
Padding(
padding: EdgeInsets.all(7),
child: ResetButton(),
)
],
),
),
);
}
Widget emailField(){
return StreamBuilder(
stream: bloc.email,
builder: (context, snapshot){
return TextFormField(
decoration: const InputDecoration(
labelText: 'Email',
errorText: snapshot.error,
),
keyboardType: TextInputType.emailAddress,
onChanged: bloc.changeEmail,
);
},
);
}
Widget passwordField(){
return StreamBuilder(
stream: bloc.pass,
builder: (context, snapshot){
return TextFormField(
decoration: const InputDecoration(
labelText: 'Password'
errorText: snapshot.error,
),
obscureText: true,
);
},
);
}
Widget submitButton(){
return ElevatedButton(
child: Text('SUBMIT'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(getColor),
),
onPressed: (){},
);
}
Widget ResetButton(){
return ElevatedButton(
child: Text('RESET'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(getColor),
),
onPressed: (){
form_key.currentState!.reset();
}
);
}
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.orange.shade600;
}
return Colors.blue.shade400;
}
}
The code of my bloc class:
class Bloc with Validators{
final _email = StreamController<String?>();
final _pass = StreamController<String?>();
//get access to stream
Stream<String?> get email => _email.stream.transform(validate_email);
Stream<String?> get pass => _pass.stream.transform(validate_password);
//change new data
Function(String?) get changeEmail => _email.sink.add;
Function(String?) get changePass => _pass.sink.add;
dispose(){
_email.close();
_pass.close();
}
}
And here is validator class:
class Validators{
final validate_email = StreamTransformer<String?, String?>.fromHandlers(
handleData: (String? email, sink){
if(email!.contains('@')){
sink.add(email);
}else{
sink.addError('Enter valid email');
}
}
);
final validate_password = StreamTransformer<String?, String?>.fromHandlers(
handleData: (String? pass, sink){
if(pass!.length < 4){
sink.addError('Enter valid password');
}else{
sink.add(pass);
}
}
);
}
Upvotes: 0
Views: 1183
Reputation: 95
Interestingly no one knows the solution as they didn't face the problem.
You've to just remove the const keyword before InputDecoration(),
The below code will not work as it has the const
keyword -
TextFormField(
decoration: const InputDecoration(
labelText: 'Email', errorText: snapshot.error),
keyboardType: TextInputType.emailAddress,
onChanged: bloc.changeEmail,
);
But this piece of code will work as it does not have the const
keyword -
TextFormField(
decoration: InputDecoration(
labelText: 'Email', errorText: snapshot.error),
keyboardType: TextInputType.emailAddress,
onChanged: bloc.changeEmail,
);
Upvotes: 1
Reputation: 12353
errorText: snapshot.hasError ? snapshot.error.toString() : "",
This will check if there is an error before converting it to a string. If there is no error, it'll prevent runtime null exceptions as well.
Upvotes: 2