Reputation: 137
I'm working on this activity-chart using firebase and I wanted to implement the logic for retrieving the data from Firebase. To get the data I wrote the following method:
static Future<double> spotData(String day, queryDocumentSnapshot) async {
final documentSnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid.toString())
.collection('activity')
.doc('${globals.year}')
.collection('week${globals.week}')
.doc(day.toString())
.get();
if (documentSnapshot.exists) {
print('Document exists');
return documentSnapshot['usage'].toDouble();
} else {
print('Document doesnt exist');
return 0;
}
// return 0; // you don't need this anymore
}
I thought it should work but turns out 0 is returned... I think that's because of the "return 0;" at the end of the method... I tried removing it but I can't since I the method could return null and flutter null safety, rightfully so, prevents that from happening... In my Console I get the Output "Document exists" - that's why I believe, that the basic if-statement logic works but I need some help with the return statement...
I'm very thankful for all kinds of help:)
class SomellierChart extends StatefulWidget {
SomellierChart(
{Key? key,
required this.color,
required this.textColor,
required this.queryDocumentSnapshot})
: super(key: key);
Color textColor;
Color color;
List<QueryDocumentSnapshot> queryDocumentSnapshot;
@override
_SomellierChartState createState() => _SomellierChartState();
}
class _SomellierChartState extends State<SomellierChart> {
static Future<double> spotData(String day, queryDocumentSnapshot) async {
final documentSnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid.toString())
.collection('activity')
.doc('${globals.year}')
.collection('week${globals.week}')
.doc(day.toString())
.get();
if (documentSnapshot.exists) {
print('Document exists');
return documentSnapshot['usage'].toDouble();
} else {
print('Document doesnt exist');
return 0;
}
}
@override
Widget build(BuildContext context) {
return LineChart(
LineChartData(
gridData: FlGridData(
show: false,
),
titlesData: FlTitlesData(
show: true,
rightTitles: SideTitles(showTitles: false),
topTitles: SideTitles(showTitles: false),
leftTitles: SideTitles(showTitles: false),
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 20,
interval: 1,
getTextStyles: (context, value) => GoogleFonts.poppins(
textStyle: TextStyle(
color: Theme.of(context).indicatorColor,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
getTitles: (value) {
switch (value.toInt()) {
case 0:
return 'Mon';
case 2:
return 'Tue';
case 4:
return 'Wed';
case 6:
return 'Thu';
case 8:
return 'Fri';
case 10:
return 'Sat';
case 12:
return 'Sun';
}
return '';
},
margin: 5,
),
),
borderData: FlBorderData(show: false),
minX: 0,
maxX: 12,
minY: 0,
maxY: 3,
lineBarsData: [
LineChartBarData(
spots: [
FlSpot(0, spotData('1', widget.queryDocumentSnapshot)),
FlSpot(2, spotData('2', widget.queryDocumentSnapshot)),
FlSpot(4, spotData('3', widget.queryDocumentSnapshot)),
FlSpot(6, spotData('4', widget.queryDocumentSnapshot)),
FlSpot(8, spotData('5', widget.queryDocumentSnapshot)),
FlSpot(10, spotData('6', widget.queryDocumentSnapshot)),
FlSpot(12, spotData('7', widget.queryDocumentSnapshot)),
],
isCurved: true,
curveSmoothness: 0.5,
preventCurveOverShooting: true,
colors: [widget.textColor],
barWidth: 3,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: [
widget.color.withOpacity(0.4),
],
),
),
],
),
);
}
}
this is the code im currently using... I made it stateful because I thought maybe I could update the UI that way but I dont believe that's necessary... How should I implement the FutureBuilder?
Upvotes: 0
Views: 265
Reputation: 5020
You are making a request to firebase, all requests to firebase are asynchronous, meaning they might be processed immediately, or after a while or at some point or another, which is why you are using the .then
.
So basically, your function runs, gets to the asynchronous calculation, continues, reaches the return 0
. returns, and only then, the .then
method calls itself and you get to work with the result, by that time, your function is long over and it already returned 0, because your original function is synchronous.
To fix this, you must make your original function asynchronous, and use the await keyword:
static Future<double> spotData(String day, queryDocumentSnapshot) async {
final documentSnapshot = await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid.toString())
.collection('activity')
.doc('${globals.year}')
.collection('week${globals.week}')
.doc(day.toString())
.get();
if (documentSnapshot.exists) {
print('Document exists');
return documentSnapshot['usage'].toDouble();
} else {
print('Document doesnt exist');
return 0;
}
// return 0; // you don't need this anymore
}
The problem of course it that you now return a future instead of the double, to use the future on UI you probably will need a FutureBuilder
Upvotes: 1