edn
edn

Reputation: 2193

Cannot convert Future<String> to String and use in Dart (Flutter)

I try to implement Firebase authentication in my mobile app. (I am very new to this..)

I have the following code which attempts to create the user for the first time:

class WpAuthService {
  FirebaseAuth _auth = FirebaseAuth.instance;

  Stream<WpUser> get wpUser {
    return _auth.authStateChanges().map((User firebaseUser) =>
        (firebaseUser != null) ? WpUser(uid: firebaseUser.uid) : null);
  }

  Future<String> createUserWithEmail(email, password) async {
    UserCredential userCredential;
    try {
      userCredential = await _auth.createUserWithEmailAndPassword(
          email: email, password: password);
    } on FirebaseAuthException catch (e) {
      print(e.code + " - " + e.message);
      return e.message;
    }

    return 'SUCCESS';
  }
}

And in another file, I am trying to call the createUserWithEmail function as following:

class SignupForm extends StatefulWidget {
  @override
  _SignupFormState createState() => _SignupFormState();
}

class _SignupFormState extends State<SignupForm> {
  final _formKey = GlobalKey<FormState>();
  var _userEmail = "";
  var _userPassword = "";

  String _opResult;

  void _trySubmit() {
    final isValid = _formKey.currentState.validate();
    FocusScope.of(context).unfocus();

    if (isValid) {
      _formKey.currentState.save();

      WpAuthService()
          .createUserWithEmail(_userEmail, _userPassword)
          .then((value) {
        setState(() {
          _opResult = value;
        });
      });

      print('MESSAGE:');
      print(_opResult);
      if (_opResult != 'SUCCESS') {
        Scaffold.of(context).showSnackBar(
          SnackBar(
            content: Text(_opResult),
            backgroundColor: Theme.of(context).errorColor,
          ),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Card(
        margin: EdgeInsets.all(20),
        child: SingleChildScrollView(
          child: Padding(
            padding: EdgeInsets.all(16),
            child: Form(
              key: _formKey,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  TextFormField(
                    key: ValueKey('email'),
                    validator: (value) {
                      if (value.isEmpty || !value.contains('@')) {
                        return 'Please enter a valid email address.';
                      }
                      return null;
                    },
                    keyboardType: TextInputType.emailAddress,
                    decoration: InputDecoration(labelText: 'Email address'),
                    onSaved: (value) {
                      _userEmail = value;
                    },
                  ),
                  TextFormField(
                    key: ValueKey('password'),
                    validator: (value) {
                      if (value.isEmpty || value.length < 7) {
                        return 'Password must be at least 7 characters long.';
                      }
                      return null;
                    },
                    decoration: InputDecoration(labelText: 'Password'),
                    obscureText: true,
                    onSaved: (value) {
                      _userPassword = value;
                    },
                  ),
                  SizedBox(height: 12),
                  RaisedButton(
                    child: Text('Sign up',
                        style: Theme.of(context).textTheme.headline6),
                    onPressed: _trySubmit,
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

When I run the above piece of code, it prints out the following:

I/flutter ( 4032): MESSAGE:
I/flutter ( 4032): null

════════ Exception caught by gesture ═══════════════════════════════════════════
The following assertion was thrown while handling a gesture:
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'

Looking at some other examples, I expect my implementation to work but something is seemingly wrong. How can I use the return value as String from the createUserWithEmail function?

Upvotes: 0

Views: 457

Answers (3)

edn
edn

Reputation: 2193

Solved.

In the createUserWithEmail function, I was returning String values as the following:

return e.message;
return 'SUCCESS';

I updated it so that the function now returns as stated below:

return Future.value(e.message);
return Future.value('SUCCESS');

Everything else is the same and it worked.

But I saw some other examples where people were just returning String values from their functions. My problem is solved but is this behavior really expected? You are more than welcome to educate me.

Upvotes: 0

medyas
medyas

Reputation: 1286

by default your _opResult variable is null and your passing it to the Text widget of the Snackbar which throws that assertion. You need either to first wait for the response to return or change your code to be inside the then method.

void _trySubmit() {
    final isValid = _formKey.currentState.validate();
    FocusScope.of(context).unfocus();

    if (isValid) {
      _formKey.currentState.save();

      WpAuthService()
          .createUserWithEmail(_userEmail, _userPassword)
          .then((value) {

        setState(() {
          _opResult = value;
        });

        print('MESSAGE:');
        print(_opResult);
        if (_opResult != 'SUCCESS') {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text(_opResult),
              backgroundColor: Theme.of(context).errorColor,
            ),
          );
        }
      });

    }
  }

Upvotes: 2

Akif
Akif

Reputation: 7660

Your _opResult is null. And it is not equal to 'SUCCESS'. And you are trying to set it into Text() widget. Text widget requires a string parameter, not null.

You can set a default string when initializing the _opResult. Like this:

  String _opResult = "";


  print('MESSAGE:');
  print(_opResult);
  if (_opResult != 'SUCCESS') {
    Scaffold.of(context).showSnackBar(
      SnackBar(
        content: Text(_opResult),
        backgroundColor: Theme.of(context).errorColor,
      ),
    );
  }

Upvotes: 1

Related Questions