Skip to content
Advertisement

Flutter/Firestore : How do I display data from doc in a ListTile?

I am new to Flutter/Firebase/Firestore etc.. so I am struggling a bit. I want to grab the data from the documents in my ‘users’ collection in Firestore and display it in my account information page. I have spent hours messing around with this and I am stuck. If anybody could help me out that would be wonderful!

Here are some samples of what my code, app, and firestore look like.

Code:

signup.dart – this is the page that creates the doc in Firebase on signup

class SignUp extends StatefulWidget {
  const SignUp({Key? key}) : super(key: key);

  @override
  State<SignUp> createState() => _SignUpState();
}

class _SignUpState extends State<SignUp> {
  var emailController = TextEditingController();
  var passwordController = TextEditingController();
  /* var docId = FirebaseFirestore.instance.collection('users').doc().id; */
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _phoneNumberController = TextEditingController();
  final TextEditingController _companyNameController = TextEditingController();
  final FirebaseAuth auth = FirebaseAuth.instance;

  @override
  Widget build(BuildContext context) {

    String docId;
    docId = emailController.text;

    final User? user = auth.currentUser;
    double w = MediaQuery.of(context).size.width;
    double h = MediaQuery.of(context).size.height;
    return Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: Colors.white,
      body: Column(
        children: [
          Container(
            width: w,
            height: h * 0.27,
            decoration: const BoxDecoration(
              image: DecorationImage(
                image: AssetImage("assets/loginsignupheader.png"),
                fit: BoxFit.fitWidth,
              ),
            ),
          ),
          Container(
            margin: const EdgeInsets.only(left: 30, right: 20),
            width: w,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                const Text(
                  'Sign up for an account',
                  style: TextStyle(fontSize: 25, color: Colors.grey),
                ),
                const SizedBox(height: 35),
                Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(30),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 10,
                            spreadRadius: 7,
                            offset: const Offset(1, 1),
                            color: Colors.grey.withOpacity(0.2))
                      ]),
                  child: TextField(
                    controller: _usernameController,
                    decoration: InputDecoration(
                      hintText: 'Username',
                      prefixIcon: const Icon(Icons.person),
                      focusedBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      enabledBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 35),
                Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(30),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 10,
                            spreadRadius: 7,
                            offset: const Offset(1, 1),
                            color: Colors.grey.withOpacity(0.2))
                      ]),
                  child: TextField(
                    controller: _companyNameController,
                    decoration: InputDecoration(
                      hintText: 'Company Name',
                      prefixIcon: const Icon(Icons.business_center),
                      focusedBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      enabledBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 35),
                Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(30),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 10,
                            spreadRadius: 7,
                            offset: const Offset(1, 1),
                            color: Colors.grey.withOpacity(0.2))
                      ]),
                  child: TextField(
                    controller: _phoneNumberController,
                    decoration: InputDecoration(
                      hintText: 'Phone Number',
                      prefixIcon: const Icon(Icons.phone),
                      focusedBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      enabledBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 35),
                Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(30),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 10,
                            spreadRadius: 7,
                            offset: const Offset(1, 1),
                            color: Colors.grey.withOpacity(0.2))
                      ]),
                  child: TextField(
                    controller: emailController,
                    decoration: InputDecoration(
                      hintText: 'Email',
                      prefixIcon: const Icon(Icons.email_outlined),
                      focusedBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      enabledBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 35),
                Container(
                  decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(30),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 10,
                            spreadRadius: 7,
                            offset: const Offset(1, 1),
                            color: Colors.grey.withOpacity(0.2))
                      ]),
                  child: TextField(
                    controller: passwordController,
                    obscureText: true,
                    decoration: InputDecoration(
                      hintText: 'Password',
                      prefixIcon: const Icon(Icons.password),
                      focusedBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      enabledBorder: OutlineInputBorder(
                          borderRadius: BorderRadius.circular(30),
                          borderSide: const BorderSide(
                              color: Colors.white, width: 1.0)),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(30),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          GestureDetector(
            onTap: () async {
              AuthController.instance.register(
                  emailController.text.trim(), passwordController.text.trim());
              FirebaseFirestore.instance.collection('users').doc(docId).set({
                'username': _usernameController.text,
                'phone': _phoneNumberController.text,
                'company_name': _companyNameController.text,
                'email': emailController.text
              });
            },
            child: Container(
                width: w * .5,
                height: h * .06,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(30),
                  image: const DecorationImage(
                    image: AssetImage("assets/button.png"),
                    fit: BoxFit.cover,
                  ),
                ),
                child: const Center(
                  child: Text(
                    'Sign Up',
                    style: TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                        color: Colors.white),
                  ),
                )),
          ),
          SizedBox(height: w * 0.1),
          RichText(
              text: TextSpan(
                  text: "Already have an account?",
                  style: const TextStyle(color: Colors.grey, fontSize: 20),
                  children: [
                TextSpan(
                    text: "  Login",
                    style: const TextStyle(
                        color: Colors.grey,
                        fontSize: 20,
                        fontWeight: FontWeight.bold),
                    recognizer: TapGestureRecognizer()
                      ..onTap = () {
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) => const Login()));
                      }),
              ])),
        ],
      ),
    );
  }
}

account.dart – this is the page I want to display my Firestore data on

class Account extends StatefulWidget {
const Account({Key? key}) : super(key: key);

  @override
  State<Account> createState() => _AccountState();
}

class _AccountState extends State<Account> {

@override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey.shade50,
      body: Stack(
        fit: StackFit.expand,
        children: [
          SingleChildScrollView(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                const SizedBox(height: 10),
                const Text(
                  'Account Settings & Info',
                  style: TextStyle(
                      fontSize: 20,
                      fontWeight: FontWeight.bold,
                      color: Colors.black),
                ),
                Card(
                  elevation: 2.0,
                  margin: const EdgeInsets.fromLTRB(16, 8.0, 16, 16.0),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10)),
                  child: Column(
                    children: <Widget>[
                      const SizedBox(height: 20),
                      Container(
                        width: 75,
                        height: 75,
                        decoration: BoxDecoration(
                          color: Colors.grey[200],
                          borderRadius: BorderRadius.circular(15),
                          image: const DecorationImage(image: AssetImage('assets/tclogotransparent.png'), fit: BoxFit.cover)
                        ),
                      ),
                      const SizedBox(height: 20),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.person,
                          color: Colors.black,
                        ),
                        title: Text('Username: $username'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail()));
                        },
                      ),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.business_center,
                          color: Colors.black,
                        ),
                        title: Text('Company Name: $companyName'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail()));
                        },),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.phone,
                          color: Colors.black,
                        ),
                        title: Text('Phone Number: $phoneNumber'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail()));
                        },
                      ),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.email_outlined,
                          color: Colors.black,
                        ),
                        title: Text('E-Mail: $emailAddress'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangeEmail()));
                        },
                      ),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.key,
                          color: Colors.black,
                        ),
                        title: const Text('Change Password'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          Navigator.push(context, MaterialPageRoute(builder: (context) => const ChangePassword()));
                        },
                      ),
                      const BuildDivider(),
                      ListTile(
                        leading: const Icon(
                          Icons.upload,
                          color: Colors.black,
                        ),
                        title: const Text('Upload Profile Picture'),
                        trailing: const Icon(Icons.keyboard_arrow_right),
                        onTap: () {
                          
                        },
                      ),
                    ],
                  ),
                ),
                Card(
                  color: Colors.red[50],
                  elevation: 2.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(10)),
                  margin: const EdgeInsets.all(16),
                  child: ListTile(
                    onTap: () {
                      AuthController.instance.signOut();
                    },
                    title: const Text('Log Out', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red),),
                    leading: const Icon(Icons.logout_outlined, color: Colors.red)
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Firestore Docs – I want to take this data and display it in the account page shown below

Edit: I have the document ids being set as the users email, I wanted to try an easy way to recall the document per account. If this is wrong please let me know.

https://i.stack.imgur.com/53TOS.png

Account Page – These are the fields I want to fill with the data, they all say N/A because I have a separate temporary file that uses constants to set those values

https://i.stack.imgur.com/eoHUE.png

Edit: Edited account.dart throws a _CastError

https://i.stack.imgur.com/YRRz9.png

Advertisement

Answer

I have figured out the solution to my issue. In the _AccountState class I added the following lines of code and it seemed to work for me.

I added this above the _AccountState class..

final FirebaseAuth _firebaseAuth = FirebaseAuth.instance

then inside the class I added this code above the build widget..

      void _getData() async {
    User? user = _firebaseAuth.currentUser;
    FirebaseFirestore.instance.collection('users').doc(user?.email).snapshots().listen((userData) {
      setState(() {
        username = userData.data()!['username'];
        companyName = userData.data()!['company_name'];
        phoneNumber = userData.data()!['phone'];
        emailAddress = userData.data()!['email'];
      });
    });
  }

  @override


void initState() {
    super.initState();
    _getData();
  }

After adding that into the state I just declared each variable in the title of my ListTiles and it seemed to work

ListTile(
   leading: const Icon(
     Icons.person,
     color: Colors.black,
   ),
   title: Text("Username: $username"),
   trailing: const Icon(Icons.keyboard_arrow_right),
   onTap: () {},
   ),
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement