type '(dynamic) => Null' is not a subtype of 'TextEditingController?'

I've been trying to accept user input in an extracted TextFormField method(Name, contact and email) and then save them to my firestore database using TextEditingController. Here lies the case after accepting the input, the name and email controller always displays the same input. After saving, even for test purposes, the database always shows that only null values have been returned from the controllers... Please help me solve this problem... Snippet of the code:

   class Profile extends StatefulWidget {
  final String email;
  Profile({Key key, this.email}) : super(key: key);
  get user => AuthService();

  @override
  _ProfileState createState() => _ProfileState(email);
}

class _ProfileState extends State<Profile> {
  String email;
  String contain;
  _ProfileState(this.email);
  bool showPhone = false;
  //Text editing controller
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _phoneController = TextEditingController();
  final TextEditingController _nameController = TextEditingController();

  // initState
  @override
  void initState() {
    super.initState();
    _emailController.addListener(() {
      final String text = _emailController.text;
      _emailController.value = _emailController.value.copyWith(
        text: text,
        selection:
            TextSelection(baseOffset: text.length, extentOffset: text.length),
        composing: TextRange.empty,
      );
    });

    _phoneController.addListener(() {
      final String contact = _phoneController.text;
      _phoneController.value = _phoneController.value.copyWith(
        text: contact,
        selection: TextSelection(
          baseOffset: contact.length,
          extentOffset: contact.length,
        ),
        composing: TextRange.empty,
      );
    });

    _nameController.addListener(() {
      final String contact = _nameController.text;
      _nameController.value = _nameController.value.copyWith(
        text: contact,
        selection: TextSelection(
          baseOffset: contact.length,
          extentOffset: contact.length,
        ),
        composing: TextRange.empty,
      );
    });
  }

  @override
  void dispose() {
    // Clean up the controller when the widget is removed from the
    // widget tree.
    _emailController.dispose();
    _phoneController.dispose();
    _nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final FirebaseAuth _auth = FirebaseAuth.instance;
    bool loading = false;
    final _formKey = GlobalKey<FormState>();
    final doc = Database();
    final ThemeData themeData = Theme.of(context);
    String name, email, contact;

    return loading
        ? Loading()
        : SafeArea(
            child: StreamBuilder<UserData>(
              stream: Database(uid: doc.uid).userData,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  UserData userData = snapshot.data;
                  return Scaffold(
                    appBar: AppBar(
                      backgroundColor: Aqua,
                      elevation: 1,
                      title: Text(
                        'Edit Profile Info',
                        style: themeData.textTheme.headline1.copyWith(
                          color: White,
                          fontSize: 22,
                          letterSpacing: 0.75,
                        ),
                      ),
                    ),
                    body: new Container(
                      height: window.physicalSize.height * 0.85,
                      padding: const EdgeInsets.only(
                        left: 16,
                        right: 16,
                        top: 25,
                      ),
                      child: SingleChildScrollView(
                        child: Column(
                          children: <Widget>[
                            new Center(
                              child: new Stack(
                                children: [
                                  addVertical(20),
                                  Container(
                                    width: 190,
                                    height: 190,
                                    decoration: BoxDecoration(
                                      border: Border.all(
                                        width: 5,
                                        color: Theme.of(context)
                                            .scaffoldBackgroundColor,
                                      ),
                                      boxShadow: [
                                        BoxShadow(
                                          blurRadius: 15,
                                          spreadRadius: 5,
                                          color: Cyan.withOpacity(0.5),
                                          offset: Offset(0, 15),
                                        ),
                                      ],
                                      shape: BoxShape.circle,
                                      image: DecorationImage(
                                        image: AssetImage(
                                            "assets/images/IMG2.jpg"),
                                        fit: BoxFit.cover,
                                      ),
                                    ),
                                  ),
                                  Positioned(
                                    bottom: 0,
                                    right: 0,
                                    child: Container(
                                      height: 55,
                                      width: 55,
                                      decoration: BoxDecoration(
                                        shape: BoxShape.circle,
                                        border: Border.all(
                                          width: 5,
                                          color: Theme.of(context)
                                              .scaffoldBackgroundColor,
                                        ),
                                        color: Cyan,
                                      ),
                                      child: IconButton(
                                        icon: Icon(
                                          Icons.edit,
                                          color: Dark_Blue,
                                        ),
                                        onPressed:
                                            () {}, // change profile picture
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            addVertical(30),
                            Form(
                              key: _formKey,
                              child: Padding(
                                padding: const EdgeInsets.only(
                                    top: 25, left: 35, right: 35, bottom: 10),
                                child: SingleChildScrollView(
                                  child: Column(
                                    children: <Widget>[
                                      buildTextFormField(
                                        "Full Name",
                                        userData.fname ??
                                            "Enter Full Name here...",
                                        false,
                                        false ?? null,
                                      ),
                                      addVertical(15),
                                      buildTextFormField(
                                        "Contact",
                                        userData.contact ?? "020 *** ****",
                                        true,
                                        false ?? null,
                                      ),
                                      addVertical(15),
                                      buildTextFormField(
                                        "E-mail",
                                        userData.email ?? "[email protected]",
                                        false,
                                        true ?? null,
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ),
                            addVertical(35),
                            Padding(
                              padding: const EdgeInsets.only(
                                  left: 35, right: 35, top: 25),
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  ElevatedButton(
                                    style: ElevatedButton.styleFrom(
                                      shape: RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(20),
                                      ),
                                      primary: White,
                                    ),
                                    onPressed: () {
                                      Navigator.pop(context);
                                    },
                                    child: Text(
                                      "CANCEL",
                                      style: themeData.textTheme.bodyText1
                                          .copyWith(
                                        letterSpacing: 1.25,
                                        fontWeight: FontWeight.bold,
                                        fontSize: 18,
                                        color: Mid_Blue,
                                      ),
                                    ),
                                  ),
                                  ElevatedButton(
                                    onPressed: () async {
                                      if (_formKey.currentState.validate()) {
                                        setState(() => loading = true);
                                        dynamic result =
                                            await _auth.currentUser;
                                        // User person = result.user;
                                        if (result != null) {
                                          await Database(uid: doc.uid)
                                              .updateData(
                                            "$name",
                                            "$email",
                                            "$contact",
                                          );
                                          Toast.show(
                                            "Your details have been successfully updated!",
                                            context,
                                            duration: Toast.LENGTH_LONG,
                                            gravity: Toast.BOTTOM,
                                          );
                                          setState(() => loading = false);
                                          Navigator.push(
                                              context,
                                              MaterialPageRoute(
                                                  builder: (context) =>
                                                      Homepage()));
                                        } else {
                                          Toast.show(
                                            "Please try again later",
                                            context,
                                            gravity: Toast.BOTTOM,
                                            duration: Toast.LENGTH_LONG,
                                          );
                                        }
                                      }
                                    },
                                    style: ElevatedButton.styleFrom(
                                      elevation: 2,
                                      primary: Colors.green[300],
                                      shape: new RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(20),
                                      ), //!elevatedButton background
                                    ),
                                    child: Text(
                                      "SAVE",
                                      style: TextStyle(
                                        fontSize: 18,
                                        letterSpacing: 2.2,
                                        color: White,
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                          //),
                        ),
                      ),
                    ),
                  );
                } else {
                  return Loading();
                }
              },
            ),
          );
  }

  Widget buildTextFormField(
    String labelText,
    String placeholder,
    bool isPhone,
    bool isEmail,
  ) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 10),
      child: TextField(
        onSubmitted: isPhone || isEmail
            ? (value) {
                value = _phoneController.toString() != null
                    ? _emailController.toString() != null
                    : _nameController;
              }
            : null,
        controller: isEmail || isPhone
            ? (value) {
                value = _emailController.toString() != null
                    ? _nameController.toString() != null
                    : _phoneController;
              }
            : _emailController,
        obscureText: isPhone ? showPhone : false,
        decoration: InputDecoration(
          suffixIcon: isPhone
              ? IconButton(
                  onPressed: () => setState(() => showPhone = !showPhone),
                  icon: Icon(
                    Icons.remove_red_eye,
                    color: Red,
                  ),
                )
              : null, //!This makes the icon appear only for the password field
          contentPadding: EdgeInsets.only(bottom: 3),
          labelText: labelText,
          labelStyle: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Aqua,
          ),
          floatingLabelBehavior: FloatingLabelBehavior.always,
          hintText: placeholder,
          hintStyle: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Cyan,
          ),
        ),
        keyboardType:
            isPhone ? TextInputType.phone : TextInputType.emailAddress,
      ),
    );
  }
}

Upvotes: 0

Views: 250

Answers (1)

Peter Obiechina
Peter Obiechina

Reputation: 2835

This is the function that builds name textField

buildTextFormField(
  "Full Name",
  userData.fname ?? "Enter Full Name here...",
  false, // isPhone
  false ?? null, // isEmail
),

From here we can see that isPhone = false; isEmail = false;

This is the function for the and controller in TextFormField:

controller: isEmail || isPhone
    ? (value) {
        value = _emailController.toString() != null
            ? _nameController.toString() != null
            : _phoneController;
      }
    : _emailController,

Since isEmail and isPhone are both false, it returns _emailController for name Textfield. So name is being updated on email textfield.

The function for onSubmitted() returns null if isEmail & isPhone are both false. Therefore, for name field, it will return null as the value (probably why you are getting null in the database).

I have tried to better organise the code below:

class MyHomePage extends StatefulWidget {
  final String email;
  MyHomePage({Key key, this.email}) : super(key: key);
  get user => AuthService();

  @override
  _MyHomePageState createState() => _MyHomePageState(email);
}

class _MyHomePageState extends State<MyHomePage> {
  String email;
  // not used in this class
  String contain;
  _MyHomePageState(this.email);
  bool showPhone = false;
  //Text editing controller
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _phoneController = TextEditingController();
  final TextEditingController _nameController = TextEditingController();

  @override
  void dispose() {
    // Clean up the controller when the widget is removed from the
    // widget tree.
    _emailController.dispose();
    _phoneController.dispose();
    _nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final FirebaseAuth _auth = FirebaseAuth.instance;
    bool loading = false;
    final _formKey = GlobalKey<FormState>();
    final doc = Database();
    final ThemeData themeData = Theme.of(context);

    return loading
        ? Loading()
        : SafeArea(
            child: StreamBuilder<UserData>(
              stream: Database(uid: doc.uid).userData,
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  UserData userData = snapshot.data;
                  _emailController.text = userData.email;
                  _phoneController.text = userData.phone;
                  _nameController.text = userData.name;

                  return Scaffold(
                    appBar: AppBar(
                      backgroundColor: Aqua,
                      elevation: 1,
                      title: Text(
                        'Edit Profile Info',
                        style: themeData.textTheme.headline1.copyWith(
                          color: White,
                          fontSize: 22,
                          letterSpacing: 0.75,
                        ),
                      ),
                    ),
                    body: new Container(
                      height: window.physicalSize.height * 0.85,
                      padding: const EdgeInsets.only(
                        left: 16,
                        right: 16,
                        top: 25,
                      ),
                      child: SingleChildScrollView(
                        child: Column(
                          children: <Widget>[
                            new Center(
                              child: new Stack(
                                children: [
                                  addVertical(20),
                                  Container(
                                    width: 190,
                                    height: 190,
                                    decoration: BoxDecoration(
                                      border: Border.all(
                                        width: 5,
                                        color: Theme.of(context)
                                            .scaffoldBackgroundColor,
                                      ),
                                      boxShadow: [
                                        BoxShadow(
                                          blurRadius: 15,
                                          spreadRadius: 5,
                                          color: Cyan.withOpacity(0.5),
                                          offset: Offset(0, 15),
                                        ),
                                      ],
                                      shape: BoxShape.circle,
                                      image: DecorationImage(
                                        image: AssetImage(
                                            "assets/images/IMG2.jpg"),
                                        fit: BoxFit.cover,
                                      ),
                                    ),
                                  ),
                                  Positioned(
                                    bottom: 0,
                                    right: 0,
                                    child: Container(
                                      height: 55,
                                      width: 55,
                                      decoration: BoxDecoration(
                                        shape: BoxShape.circle,
                                        border: Border.all(
                                          width: 5,
                                          color: Theme.of(context)
                                              .scaffoldBackgroundColor,
                                        ),
                                        color: Cyan,
                                      ),
                                      child: IconButton(
                                        icon: Icon(
                                          Icons.edit,
                                          color: Dark_Blue,
                                        ),
                                        onPressed:
                                            () {}, // change profile picture
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            addVertical(30),
                            Form(
                              key: _formKey,
                              child: Padding(
                                padding: const EdgeInsets.only(
                                    top: 25, left: 35, right: 35, bottom: 10),
                                child: SingleChildScrollView(
                                  child: Column(
                                    children: <Widget>[
                                      buildTextFormField(
                                        "Full Name",
                                        "Enter Full Name here...",
                                        false,
                                        _nameController,
                                      ),
                                      addVertical(15),
                                      buildTextFormField(
                                        "Contact",
                                        "020 *** ****",
                                        true,
                                        _phoneController,
                                      ),
                                      addVertical(15),
                                      buildTextFormField(
                                        "E-mail",
                                        "[email protected]",
                                        false,
                                        _nameController,
                                      ),
                                    ],
                                  ),
                                ),
                              ),
                            ),
                            addVertical(35),
                            Padding(
                              padding: const EdgeInsets.only(
                                  left: 35, right: 35, top: 25),
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceBetween,
                                children: [
                                  ElevatedButton(
                                    style: ElevatedButton.styleFrom(
                                      shape: RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(20),
                                      ),
                                      primary: White,
                                    ),
                                    onPressed: () {
                                      Navigator.pop(context);
                                    },
                                    child: Text(
                                      "CANCEL",
                                      style: themeData.textTheme.bodyText1
                                          .copyWith(
                                        letterSpacing: 1.25,
                                        fontWeight: FontWeight.bold,
                                        fontSize: 18,
                                        color: Mid_Blue,
                                      ),
                                    ),
                                  ),
                                  ElevatedButton(
                                    onPressed: () async {
                                      if (_formKey.currentState.validate()) {
                                        setState(() => loading = true);
                                        dynamic result =
                                            await _auth.currentUser;
                                        // User person = result.user;
                                        if (result != null) {
                                          await Database(uid: doc.uid)
                                              .updateData(
                                            _nameController.text,
                                            _emailController.text,
                                            _phoneController.text,
                                          );
                                          Toast.show(
                                            "Your details have been successfully updated!",
                                            context,
                                            duration: Toast.LENGTH_LONG,
                                            gravity: Toast.BOTTOM,
                                          );
                                          setState(() => loading = false);
                                          Navigator.push(
                                              context,
                                              MaterialPageRoute(
                                                  builder: (context) =>
                                                      Homepage()));
                                        } else {
                                          Toast.show(
                                            "Please try again later",
                                            context,
                                            gravity: Toast.BOTTOM,
                                            duration: Toast.LENGTH_LONG,
                                          );
                                        }
                                      }
                                    },
                                    style: ElevatedButton.styleFrom(
                                      elevation: 2,
                                      primary: Colors.green[300],
                                      shape: new RoundedRectangleBorder(
                                        borderRadius: BorderRadius.circular(20),
                                      ), //!elevatedButton background
                                    ),
                                    child: Text(
                                      "SAVE",
                                      style: TextStyle(
                                        fontSize: 18,
                                        letterSpacing: 2.2,
                                        color: White,
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                          //),
                        ),
                      ),
                    ),
                  );
                } else {
                  return Loading();
                }
              },
            ),
          );
  }

  Widget buildTextFormField(
    String labelText,
    String placeholder,
    bool isPhone,
    TextEditingController controller,
  ) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 10),
      child: TextField(
        // onSubmitted: isPhone || isEmail
        //     ? (value) {
        //         value = _phoneController.toString() != null
        //             ? _emailController.toString() != null
        //             : _nameController;
        //       }
        //     : null,
        controller: controller,
        obscureText: isPhone ? showPhone : false,
        decoration: InputDecoration(
          suffixIcon: isPhone
              ? IconButton(
                  onPressed: () => setState(() => showPhone = !showPhone),
                  icon: Icon(
                    Icons.remove_red_eye,
                    color: Red,
                  ),
                )
              : null, //!This makes the icon appear only for the password field
          contentPadding: EdgeInsets.only(bottom: 3),
          labelText: labelText,
          labelStyle: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Aqua,
          ),
          floatingLabelBehavior: FloatingLabelBehavior.always,
          hintText: placeholder,
          hintStyle: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
            color: Cyan,
          ),
        ),
        keyboardType:
            isPhone ? TextInputType.phone : TextInputType.emailAddress,
      ),
    );
  }
}

Upvotes: 1

Related Questions