I am trying to get the length of a collection in Firebase using Flutter. I have a profile page that loads how many hikes you have done from a database, but I keep getting a Future<int> when I print the variable. How do I solve this problem?
class ProfilePage extends StatefulWidget {
#override
_ProfilePage createState() => new _ProfilePage();
}
int doneHikes;
Database temp = new Database();
class _ProfilePage extends State<ProfilePage> {
#override
void initState() {
super.initState();
_numOfDoneHikes();
}
Future<void> _numOfDoneHikes() async{
var asyncResult = await temp.numOfDoneHikes();
setState(() => doneHikes = asyncResult);
print(doneHikes);
}
numOfDoneHikes function in the Database object:
Future<int> numOfDoneHikes() async {
return Firestore.instance.collection(globalUserName)
.document("Done Hikes").collection("Hike List").snapshots().length;
}
With this code, I keep getting doneHikes printing
instance of Future<int>
You can use await:
Future<int> numOfDoneHikes() async {
return await Firestore.instance.collection(globalUserName)
.document("Done Hikes").collection("Hike List").snapshots().length;
}
in fact, you don't even need await, you can do this instead:
Future<int> numOfDoneHikes() {
return Firestore.instance.collection(globalUserName)
.document("Done Hikes").collection("Hike List").snapshots().length;
}
Related
I saw this example trying to get the User details from Firestore Firebase in Flutter. Unfortunately it gives me the error The instance member 'snap' can't be accessed in an initializer.
DocumentSnapshot snap = FirebaseFirestore.instance.collection('Users').doc().get() as DocumentSnapshot<Object?>;
String myId = snap['name'];
Yeah, you can't use snap there because you have not initialized the object.
Rather, move the usage into initState. Something like this:
class _MyHomePageState extends State<MyHomePage> {
DocumentSnapshot snap = await FirebaseFirestore.instance
.collection('Users')
.doc()
.get() as DocumentSnapshot<Object?>;
String myId;
#override
void initState() {
super.initState();
myId = snap['name'];
// should be myId = snap.get('name');
}
You can call it using async and await
String myId = '';
#override
void initState() {
super.initState();
initialize();
}
void initialize() async{
DocumentSnapshot snap = await FirebaseFirestore.instance.collection('Users').doc().get() as DocumentSnapshot<Object?>;
myId = snap['name'];
}
I am stuck for hours now on this problem.
I have no problem to access the final currentUser = loggedInUser.email;when the getCurrentUser function is defined and called in the same class (SlateScreen).
My SlateScreen Class ad MessageStream Class are both in the same .dart file. So this here works:
final firestore = Firestore.instance;
/// loggedInUser variable for fetching the user email later
FirebaseUser loggedInUser;
DatabaseMethods databaseMethods = DatabaseMethods();
class TheSlateScreen extends StatefulWidget {
static String id = 'theslate_screen';
#override
_TheSlateScreenState createState() => _TheSlateScreenState();
}
class _TheSlateScreenState extends State<TheSlateScreen> {
final _auth = FirebaseAuth.instance;
// call getCurrentUser in initState
#override
void initState() {
super.initState();
getCurrenUser();
}
getCurrentUser() async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
print(loggedInUser);
}
} catch (e) {
print(e);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
// fetch the email from my getCurrentUser function
final currentUser = loggedInUser.email;
But I get "The getter email was called on null" error if I define my getCurrentUser() function in the DatabaseMethods Class, and then call it in the SlateScreen class' via
#override
void initState() {
super.initState();
databaseMethods.getCurrentUser(_auth);
}
My DatabaseMethods Class:
class DatabaseMethods {
FirebaseUser loggedInUser;
getCurrentUser(FirebaseAuth _auth) async {
try {
final user = await _auth.currentUser();
if (user != null) {
loggedInUser = user;
}
} catch (e) {
print(e);
}
}
I tried all kind of adjustments, but didn t get anywhere...
UPDATE / SOLUTION:
Thanks to the the anwsers provided, I found a way:
in my DatabaseMethods class I simply return the user:
Class DatabaseMethods {
getCurrentUser(FirebaseAuth _auth) async {
try {
final user = await _auth.currentUser();
if (user != null) {
return user;
}
} catch (e) {
print(e);
}
}
}
and in the SlateScreen Class, I am using a helper function that I can call in initState():
#override
void initState() {
super.initState();
logInUser(_auth);
}
logInUser(_auth) async {
loggedInUser = await DatabaseMethods().getCurrentUser(_auth);
}
In this snippet:
// fetch the email from my getCurrentUser function
final currentUser = loggedInUser.email;
The loggedInUser variable is only set once the getCurrentUser method has completed. So you can't just do loggedInUser.email anywhere in your code, but can only do that after you've made sure getCurrentUser has completed.
So this would work fine:
await databaseMethods.getCurrentUser(_auth);
final currentUser = loggedInUser.email;
Given what you shared, it may be able to add that await in your initState:
#override
void initState() {
super.initState();
await databaseMethods.getCurrentUser(_auth);
}
You need to initialize loggedInUser, just do the following:
loggedInUser = await FirebaseAuth.instance.currentUser();
final currentUser = loggedInUser.email;
Future<List> getHistory() async {
List images;
final List<DocumentSnapshot> documents =
(await Firestore.instance.collection("History").getDocuments()).documents;
images = documents.map((documentSnapshot) => documentSnapshot['images']).toList();
return images;
}
Hi all, what am I doing wrong here, it never returns images. I am sure that I am not doing this the correct way so any hints would be greatly appreciated.
class _HomeScreenState extends State<HomePage> {
#override
void initState() {
super.initState();
getHistory();
}
Thank you
You're returning the images but not doing anything with the return value, Try this:
class _HomeScreenState extends State<HomePage> {
List images;
Future<List> getHistory() async {
final List<DocumentSnapshot> documents = (await
Firestore.instance.collection("History").getDocuments()).documents;
images = documents.map((documentSnapshot) => documentSnapshot['images']).toList();
}
#override
void initState() {
super.initState();
getHistory();
}
And in the widget tree use a future builder that awaits getHistory()'s results
I have a FirebaseActions class which is doing signup and signin works for me. I added a getCurrentUser method in it. I'm calling that function from my HomeScreen widget. I need to put the returned value(type= FirebaseUser) into a variable in my HomeScreen to reach loggedInUser.email. But I get this error. My question; is there any way to get a FirebaseUser type data into a Future type variable? When I write this function in HomeScreen instead of FirebasAction class, it works but is it the best practice?
FirebaseActions class
static getCurrentUser(context) async {
final user = await _auth.currentUser().catchError((error) {
Scaffold.of(context).showSnackBar(AppSnackBar.appSnackBar(error.message));
});
if (user != null) {
return user;
}
}
HomeScreen widget
class _HomeScreenState extends State<HomeScreen> {
FirebaseUser loggedInUser;
#override
void initState() {
super.initState();
loggedInUser = FirebaseActions.getCurrentUser(context);
print(loggedInUser.toString());
}
You are getting this error because you didn't specify a return type in your getCurrentUser() function.
Replace your code with the one below and everything will work fine.
To solve this issue:
Check the code below: It works perfectly fine:
Firebase Action Class
// give your function a return type
static Future<FirebaseUser> getCurrentUser(context) async {
final user = await _auth.currentUser().catchError((error) {
Scaffold.of(context).showSnackBar(AppSnackBar.appSnackBar(error.message));
});
if (user != null) {
return user;
}
}
Home Screen Widget
class _HomeScreenState extends State<HomeScreen> {
FirebaseUser loggedInUser;
#override
void initState() {
super.initState();
call the function here
logInUser();
print(loggedInUser.toString());
}
I hope this helps
UPDATE
// create a new function to log in user
void logInUser() async {
// await the result because you are invoking a future method
loggedInUser = await FirebaseActions.getCurrentUser(context);
}
You are not specified return type of method and also method is async, so you have to put await where you are calling.
static Future<FirebaseUser> getCurrentUser(context) async {
also, add await where you are calling.
loggedInUser = await FirebaseActions.getCurrentUser(context);
update:
create new function and call in that function.
callme() async{
loggedInUser = FirebaseActions.getCurrentUser(context);
print(loggedInUser.toString());
}
initstate:
#override
void initState() {
super.initState();
callme();
}
Here's how I handle async functions in my initstate:
FirebaseActions.getCurrentUser(context).then((val){loggedInUser = val});
Also make sure you specify the return type in your asynchronous function.
Future<FirebaseUser> getCurrentUser(context) async {...
I'm having a simple problem which is how to get specific values from database Firebase.
For example, I want to get the value of "name" and put it in text. How can I do that? Can you write a detailed code?
class _HomePageState extends State<HomePage> {
String myuid;
FirebaseUser currentUser;
// To get id
void _loadCurrentUser() {
FirebaseAuth.instance.currentUser().then((FirebaseUser user) {
setState(() { // call setState to rebuild the view
this.currentUser = user;
});
});
}
#override
void initState() {
super.initState();
_loadCurrentUser();
}
#override
Widget build(BuildContext context) {
myuid = currentUser.uid;
var getname;
Future<void> getName() async {
DocumentSnapshot ds =
await Firestore.instance.collection('users').document(myuid).get();
getname = ds.data['name'];
}
Try
String name;
Future<null> getName() async {
DocumentSnapshot document = await Firestore.instance.collection('users').document(FirebaseUser().uid).get();
name = document.data['name']
}
This is how you can get data from the Firestore Database Document once
val docRef = db.collection("users").document("mhPtwy..........")
docRef.get()
.addOnSuccessListener { document ->
if (document != null) {
Log.d(TAG, "DocumentSnapshot data: ${document.data}")
} else {
Log.d(TAG, "No such document")
}
}
.addOnFailureListener { exception ->
Log.d(TAG, "get failed with ", exception)
}
This is a kind of cheeky way to get the data and store it in a variable
var name;
Future<void> getName(){
DocumentSnapshot ds = await
Firestore.instance.collection('users').document(uid).get();
name = ds.data['name']
}
then just throw that in your text field
Text(name);