0

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);
      }
    }
  );
}

3 Answers3

2

You need to use

snapshot.error?.toString()
Tolga Kartal
  • 617
  • 4
  • 12
2
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.

Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49
  • it still returns an empty string, because of which it shows a red error on the text field with an empty string. Instead, as according to another answer using snapshot.error?.toString() works better. Thank you for the answer. – sharmaji saheb Aug 06 '21 at 06:02
1

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,
     );
  • Indeed. But now, it works with ```snapshot.error?.toString()``` as well as the removal of ```const```. We have to apply both solutions. – Mário Meyrelles Jul 07 '22 at 02:50