Georgios
Georgios

Reputation: 1037

Fetching Data from a Realtime Firestore Document

I have seen similar questions and answers being solved with the StreamBuilder widget.

In my case when I am implementing it my code does not await to fetch the data and just moves on (in my case, the app jumps to the next page). Thus, do I need the build a StreamBuilder Widget or is there a simple method that could work and fetch the data in realtime?

I noticed that I did not use async* with the asterisc but if I do so, then the authentication is not working.

Clarification:

The code does not enter the following lines:

if (!snapshot.hasData)
 return new Text('Loading...');
return new Text(
  snapshot.data.data['name']
 );

Also the print(test); statement prints the following:

StreamBuilder<DocumentSnapshot>

Here is the whole part:

onPressed: () async {
  setState(() {
    showSpinner = true;
  });
  try {
    LoginScreen.user =
        await _auth.signInWithEmailAndPassword(
            email: email, password: password);
    if (LoginScreen.user != null) {
      // get the users data and save them
      if (LoginScreen.user.user.uid !=
          'IDVwQXAsZas213Va0OIH2IsoU5asdaTfraBJ2') {
      Widget test = await StreamBuilder<DocumentSnapshot>(
          stream: _firestore
              .collection('Employees')
              .document(LoginScreen.user.user.uid)
              .snapshots(),
          builder: (BuildContext context,
              AsyncSnapshot<DocumentSnapshot> snapshot) {
            if (!snapshot.hasData)
              return new Text('Loading...');
            return new Text(
              snapshot.data.data['name']
            );
          },
        );
        print(test);
        Navigator.pushReplacementNamed(
            context, TabCreator.screenId);
      } else {
      }
    }
  } catch (e) {
    print(e);
    // when getting an erro stop spinner
    setState(() {
      showSpinner = false;
    });
  }
}

Update:

I created a new standard flutter project in order to see if there was something else within my code that was messing the StreamBuilder. I am still getting no output.

On a side note when I am implementing the following code within the onPressed method I am getting the wanted result:

Alternative Solution:

onPressed: () {
  DocumentReference documentReference = await Firestore.instance
      .collection('Employees')
      .document('8nss0gppzNfOBMuRz9H44dv7gSd2');
  documentReference.snapshots().listen((datasnapshot) {
    if (datasnapshot.exists) {
      print(datasnapshot.data['name'].toString());
    } else {
      print('Error!');
    }
});
}

Here is the implemented StreamBuilder implemented in the standard Flutter project:

import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  final _auth = FirebaseAuth.instance;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              'Testing',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // DocumentReference documentReference = await Firestore.instance
          //     .collection('Employees')
          //     .document('8nss0gppzNfOBMuRz9H44dv7gSd2');
          // documentReference.snapshots().listen((datasnapshot) {
          //   if (datasnapshot.exists) {
          //     print(datasnapshot.data['name'].toString());
          //   } else {
          //     print('Error!');
          //   }
          // });
          StreamBuilder<DocumentSnapshot>(
            stream: Firestore.instance
                .collection('Employees')
                .document('8nss0gppzNfOBMuRz9H44dv7gSd2')
                .snapshots(),
            builder: (BuildContext context,
                AsyncSnapshot<DocumentSnapshot> snapshot) {
              if (snapshot.hasError)
                return new Text('Error: ${snapshot.error}');
              switch (snapshot.connectionState) {
                case ConnectionState.waiting:
                  return new Text('Loading...');
                default:
                  return new Text(snapshot.data.data['name']);
              }
            },
          );
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Upvotes: 0

Views: 63

Answers (1)

Peter Haddad
Peter Haddad

Reputation: 80914

Change your code to the following:

builder: : (BuildContext context,
              AsyncSnapshot<DocumentSnapshot> snapshot) {
            if (!snapshot.hasData){
              return new Text('Loading...');
          }
          else{
              print(snapshot);
              Navigator.pushReplacementNamed(
                   context, TabCreator.screenId);
           }

Add an else block so when you have data it will enter the else and navigate to the page.


Also you need to use the StreamBuilder inside the build method not inside the onPressed function which is used to handle data processing. Example you can do the following:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  bool visible = false;
  final firestoreInstance = Firestore.instance;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            Visibility(
              child: StreamBuilder<DocumentSnapshot>(
                stream: Firestore.instance
                    .collection('users')
                    .document('FIJbBBiplAGorYzdtUQF')
                    .snapshots(),
                builder: (BuildContext context,
                    AsyncSnapshot<DocumentSnapshot> snapshot) {
                  print(snapshot);
                  if (snapshot.hasError)
                    return new Text('Error: ${snapshot.error}');
                  else if (snapshot.hasData) {
                    print(snapshot.data.data);
                    return new Text(snapshot.data.data["age"].toString());
                  }
                  return new CircularProgressIndicator();
                },
              ),
              visible: visible,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            visible = true;
          });
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

So here I also use the Visibility() widget to hide it, but when FAB button is clicked the data from firestore will appear.

Upvotes: 1

Related Questions